mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 16:42:50 -05:00
[PM-2943] Enable Nullable Repositories in Unowned Files (#4549)
* Enable Nullable In Unowned Repos * Update More Tests * Move to One If * Fix Collections * Format * Add Migrations * Move Pragma Annotation * Add Better Assert Message
This commit is contained in:
@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using User = Bit.Core.Entities.User;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public abstract class BaseEntityFrameworkRepository
|
||||
|
@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using CollectionCipher = Bit.Core.Entities.CollectionCipher;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class CollectionCipherRepository : BaseEntityFrameworkRepository, ICollectionCipherRepository
|
||||
@ -21,7 +23,7 @@ public class CollectionCipherRepository : BaseEntityFrameworkRepository, ICollec
|
||||
var entity = Mapper.Map<Models.CollectionCipher>(obj);
|
||||
dbContext.Add(entity);
|
||||
await dbContext.SaveChangesAsync();
|
||||
var organizationId = (await dbContext.Ciphers.FirstOrDefaultAsync(c => c.Id.Equals(obj.CipherId))).OrganizationId;
|
||||
var organizationId = (await dbContext.Ciphers.FirstOrDefaultAsync(c => c.Id.Equals(obj.CipherId)))?.OrganizationId;
|
||||
if (organizationId.HasValue)
|
||||
{
|
||||
await dbContext.UserBumpAccountRevisionDateByCollectionIdAsync(obj.CollectionId, organizationId.Value);
|
||||
|
@ -6,6 +6,8 @@ using Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class CollectionRepository : Repository<Core.Entities.Collection, Collection, Guid>, ICollectionRepository
|
||||
@ -110,7 +112,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Tuple<Core.Entities.Collection, CollectionAccessDetails>> GetByIdWithAccessAsync(Guid id)
|
||||
public async Task<Tuple<Core.Entities.Collection?, CollectionAccessDetails>> GetByIdWithAccessAsync(Guid id)
|
||||
{
|
||||
var collection = await base.GetByIdAsync(id);
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
@ -139,7 +141,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
var users = await userQuery.ToArrayAsync();
|
||||
var access = new CollectionAccessDetails { Users = users, Groups = groups };
|
||||
|
||||
return new Tuple<Core.Entities.Collection, CollectionAccessDetails>(collection, access);
|
||||
return new Tuple<Core.Entities.Collection?, CollectionAccessDetails>(collection, access);
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +394,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CollectionAdminDetails> GetByIdWithPermissionsAsync(Guid collectionId, Guid? userId,
|
||||
public async Task<CollectionAdminDetails?> GetByIdWithPermissionsAsync(Guid collectionId, Guid? userId,
|
||||
bool includeAccessRelationships)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
@ -400,7 +402,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = CollectionAdminDetailsQuery.ByCollectionId(collectionId, userId).Run(dbContext);
|
||||
|
||||
CollectionAdminDetails collectionDetails;
|
||||
CollectionAdminDetails? collectionDetails;
|
||||
|
||||
// SQLite does not support the GROUP BY clause
|
||||
if (dbContext.Database.IsSqlite())
|
||||
@ -474,7 +476,8 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
HidePasswords = cg.HidePasswords,
|
||||
Manage = cg.Manage
|
||||
};
|
||||
collectionDetails.Groups = await groupsQuery.ToListAsync();
|
||||
// TODO-NRE: Probably need to null check and return early
|
||||
collectionDetails!.Groups = await groupsQuery.ToListAsync();
|
||||
|
||||
var usersQuery = from cg in dbContext.CollectionUsers
|
||||
where cg.CollectionId.Equals(collectionId)
|
||||
|
@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using DP = Microsoft.AspNetCore.DataProtection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class DatabaseContext : DbContext
|
||||
|
@ -1,9 +1,12 @@
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using System.Diagnostics;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public static class DatabaseContextExtensions
|
||||
@ -11,6 +14,7 @@ public static class DatabaseContextExtensions
|
||||
public static async Task UserBumpAccountRevisionDateAsync(this DatabaseContext context, Guid userId)
|
||||
{
|
||||
var user = await context.Users.FindAsync(userId);
|
||||
Debug.Assert(user is not null, "The user id is expected to be validated as a true-in database user before making this call.");
|
||||
user.AccountRevisionDate = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class DeviceRepository : Repository<Core.Entities.Device, Device, Guid>, IDeviceRepository
|
||||
@ -24,7 +26,7 @@ public class DeviceRepository : Repository<Core.Entities.Device, Device, Guid>,
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.Device> GetByIdAsync(Guid id, Guid userId)
|
||||
public async Task<Core.Entities.Device?> GetByIdAsync(Guid id, Guid userId)
|
||||
{
|
||||
var device = await base.GetByIdAsync(id);
|
||||
if (device == null || device.UserId != userId)
|
||||
@ -35,7 +37,7 @@ public class DeviceRepository : Repository<Core.Entities.Device, Device, Guid>,
|
||||
return Mapper.Map<Core.Entities.Device>(device);
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.Device> GetByIdentifierAsync(string identifier)
|
||||
public async Task<Core.Entities.Device?> GetByIdentifierAsync(string identifier)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
@ -46,7 +48,7 @@ public class DeviceRepository : Repository<Core.Entities.Device, Device, Guid>,
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.Device> GetByIdentifierAsync(string identifier, Guid userId)
|
||||
public async Task<Core.Entities.Device?> GetByIdentifierAsync(string identifier, Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
|
@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Cipher = Bit.Core.Vault.Entities.Cipher;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class EventRepository : Repository<Core.Entities.Event, Event, Guid>, IEventRepository
|
||||
@ -28,7 +30,7 @@ public class EventRepository : Repository<Core.Entities.Event, Event, Guid>, IEv
|
||||
|
||||
public async Task CreateManyAsync(IEnumerable<IEvent> entities)
|
||||
{
|
||||
if (!entities?.Any() ?? true)
|
||||
if (entities is null || !entities.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ using Bit.Core.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class InstallationRepository : Repository<Core.Entities.Installation, Installation, Guid>, IInstallationRepository
|
||||
|
@ -2,6 +2,8 @@
|
||||
using Bit.Core.Repositories;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class MaintenanceRepository : BaseEntityFrameworkRepository, IMaintenanceRepository
|
||||
|
@ -5,6 +5,8 @@ using Bit.Core.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class OrganizationApiKeyRepository : Repository<OrganizationApiKey, Models.OrganizationApiKey, Guid>, IOrganizationApiKeyRepository
|
||||
|
@ -5,6 +5,8 @@ using Bit.Core.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class OrganizationConnectionRepository : Repository<OrganizationConnection, Models.OrganizationConnection, Guid>, IOrganizationConnectionRepository
|
||||
@ -15,7 +17,7 @@ public class OrganizationConnectionRepository : Repository<OrganizationConnectio
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<OrganizationConnection> GetByIdOrganizationIdAsync(Guid id, Guid organizationId)
|
||||
public async Task<OrganizationConnection?> GetByIdOrganizationIdAsync(Guid id, Guid organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
|
@ -6,6 +6,8 @@ using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class OrganizationDomainRepository : Repository<Core.Entities.OrganizationDomain, OrganizationDomain, Guid>, IOrganizationDomainRepository
|
||||
@ -67,7 +69,7 @@ public class OrganizationDomainRepository : Repository<Core.Entities.Organizatio
|
||||
return Mapper.Map<List<Core.Entities.OrganizationDomain>>(results);
|
||||
}
|
||||
|
||||
public async Task<OrganizationDomainSsoDetailsData> GetOrganizationDomainSsoDetailsAsync(string email)
|
||||
public async Task<OrganizationDomainSsoDetailsData?> GetOrganizationDomainSsoDetailsAsync(string email)
|
||||
{
|
||||
var domainName = new MailAddress(email).Host;
|
||||
|
||||
@ -93,7 +95,7 @@ public class OrganizationDomainRepository : Repository<Core.Entities.Organizatio
|
||||
return ssoDetails;
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.OrganizationDomain> GetDomainByIdOrganizationIdAsync(Guid id, Guid orgId)
|
||||
public async Task<Core.Entities.OrganizationDomain?> GetDomainByIdOrganizationIdAsync(Guid id, Guid orgId)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
@ -105,7 +107,7 @@ public class OrganizationDomainRepository : Repository<Core.Entities.Organizatio
|
||||
return Mapper.Map<Core.Entities.OrganizationDomain>(domain);
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.OrganizationDomain> GetDomainByOrgIdAndDomainNameAsync(Guid orgId, string domainName)
|
||||
public async Task<Core.Entities.OrganizationDomain?> GetDomainByOrgIdAndDomainNameAsync(Guid orgId, string domainName)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
@ -4,6 +4,8 @@ using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class OrganizationSponsorshipRepository : Repository<Core.Entities.OrganizationSponsorship, OrganizationSponsorship, Guid>, IOrganizationSponsorshipRepository
|
||||
@ -12,10 +14,11 @@ public class OrganizationSponsorshipRepository : Repository<Core.Entities.Organi
|
||||
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.OrganizationSponsorships)
|
||||
{ }
|
||||
|
||||
public async Task<ICollection<Guid>> CreateManyAsync(IEnumerable<Core.Entities.OrganizationSponsorship> organizationSponsorships)
|
||||
public async Task<ICollection<Guid>?> CreateManyAsync(IEnumerable<Core.Entities.OrganizationSponsorship> organizationSponsorships)
|
||||
{
|
||||
if (!organizationSponsorships.Any())
|
||||
{
|
||||
// TODO: This differs from SQL server implementation, we should have both return empty collection
|
||||
return new List<Guid>();
|
||||
}
|
||||
|
||||
@ -79,7 +82,7 @@ public class OrganizationSponsorshipRepository : Repository<Core.Entities.Organi
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.OrganizationSponsorship> GetByOfferedToEmailAsync(string email)
|
||||
public async Task<Core.Entities.OrganizationSponsorship?> GetByOfferedToEmailAsync(string email)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
@ -90,7 +93,7 @@ public class OrganizationSponsorshipRepository : Repository<Core.Entities.Organi
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.OrganizationSponsorship> GetBySponsoredOrganizationIdAsync(Guid sponsoredOrganizationId)
|
||||
public async Task<Core.Entities.OrganizationSponsorship?> GetBySponsoredOrganizationIdAsync(Guid sponsoredOrganizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
@ -101,7 +104,7 @@ public class OrganizationSponsorshipRepository : Repository<Core.Entities.Organi
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.OrganizationSponsorship> GetBySponsoringOrganizationUserIdAsync(Guid sponsoringOrganizationUserId)
|
||||
public async Task<Core.Entities.OrganizationSponsorship?> GetBySponsoringOrganizationUserIdAsync(Guid sponsoringOrganizationUserId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
|
@ -5,6 +5,8 @@ using Bit.Infrastructure.EntityFramework.Repositories.Queries;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public abstract class Repository<T, TEntity, TId> : BaseEntityFrameworkRepository, IRepository<T, TId>
|
||||
@ -20,7 +22,7 @@ public abstract class Repository<T, TEntity, TId> : BaseEntityFrameworkRepositor
|
||||
|
||||
protected Func<DatabaseContext, DbSet<TEntity>> GetDbSet { get; private set; }
|
||||
|
||||
public virtual async Task<T> GetByIdAsync(TId id)
|
||||
public virtual async Task<T?> GetByIdAsync(TId id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
|
@ -4,6 +4,8 @@ using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class TaxRateRepository : Repository<Core.Entities.TaxRate, TaxRate, string>, ITaxRateRepository
|
||||
@ -17,9 +19,9 @@ public class TaxRateRepository : Repository<Core.Entities.TaxRate, TaxRate, stri
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.FindAsync<Core.Entities.TaxRate>(model);
|
||||
entity.Active = false;
|
||||
await dbContext.SaveChangesAsync();
|
||||
await dbContext.TaxRates
|
||||
.Where(tr => tr.Id == model.Id)
|
||||
.ExecuteUpdateAsync(property => property.SetProperty(tr => tr.Active, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@ using LinqToDB;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class TransactionRepository : Repository<Core.Entities.Transaction, Transaction, Guid>, ITransactionRepository
|
||||
@ -14,7 +16,7 @@ public class TransactionRepository : Repository<Core.Entities.Transaction, Trans
|
||||
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.Transactions)
|
||||
{ }
|
||||
|
||||
public async Task<Core.Entities.Transaction> GetByGatewayIdAsync(GatewayType gatewayType, string gatewayId)
|
||||
public async Task<Core.Entities.Transaction?> GetByGatewayIdAsync(GatewayType gatewayType, string gatewayId)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using DataModel = Bit.Core.Models.Data;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
public class UserRepository : Repository<Core.Entities.User, User, Guid>, IUserRepository
|
||||
@ -14,7 +16,7 @@ public class UserRepository : Repository<Core.Entities.User, User, Guid>, IUserR
|
||||
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.Users)
|
||||
{ }
|
||||
|
||||
public async Task<Core.Entities.User> GetByEmailAsync(string email)
|
||||
public async Task<Core.Entities.User?> GetByEmailAsync(string email)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
@ -36,7 +38,7 @@ public class UserRepository : Repository<Core.Entities.User, User, Guid>, IUserR
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DataModel.UserKdfInformation> GetKdfInformationByEmailAsync(string email)
|
||||
public async Task<DataModel.UserKdfInformation?> GetKdfInformationByEmailAsync(string email)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
@ -89,7 +91,7 @@ public class UserRepository : Repository<Core.Entities.User, User, Guid>, IUserR
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetPublicKeyAsync(Guid id)
|
||||
public async Task<string?> GetPublicKeyAsync(Guid id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
@ -130,7 +132,7 @@ public class UserRepository : Repository<Core.Entities.User, User, Guid>, IUserR
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.User> GetBySsoUserAsync(string externalId, Guid? organizationId)
|
||||
public async Task<Core.Entities.User?> GetBySsoUserAsync(string externalId, Guid? organizationId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
|
Reference in New Issue
Block a user