mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
import fixes for new folder/favorite schema
This commit is contained in:
parent
09048cf98f
commit
bf18a5905d
@ -18,7 +18,6 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="1.1.2" />
|
||||
<PackageReference Include="Dapper" Version="1.50.2" />
|
||||
<PackageReference Include="DataTableProxy" Version="1.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
|
||||
<PackageReference Include="Sendgrid" Version="9.0.12" />
|
||||
<PackageReference Include="PushSharp" Version="4.0.10" />
|
||||
|
10
src/Core/Models/Table/Favorite.cs
Normal file
10
src/Core/Models/Table/Favorite.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Bit.Core.Models.Table
|
||||
{
|
||||
public class Favorite
|
||||
{
|
||||
public Guid CipherId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
}
|
||||
}
|
10
src/Core/Models/Table/FolderCipher.cs
Normal file
10
src/Core/Models/Table/FolderCipher.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Bit.Core.Models.Table
|
||||
{
|
||||
public class FolderCipher
|
||||
{
|
||||
public Guid CipherId { get; set; }
|
||||
public Guid FolderId { get; set; }
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ namespace Bit.Core.Repositories
|
||||
Task ReplaceAsync(Cipher obj, IEnumerable<Guid> subvaultIds);
|
||||
Task UpdatePartialAsync(Guid id, Guid userId, Guid? folderId, bool favorite);
|
||||
Task UpdateUserEmailPasswordAndCiphersAsync(User user, IEnumerable<Cipher> ciphers);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Favorite> favorites, IEnumerable<Folder> folders,
|
||||
IEnumerable<FolderCipher> folderCiphers);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Threading.Tasks;
|
||||
using DataTableProxy;
|
||||
using Bit.Core.Models.Table;
|
||||
using System.Data;
|
||||
using Dapper;
|
||||
@ -198,8 +197,7 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
using(var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "#TempCipher";
|
||||
|
||||
var dataTable = ciphers.ToTable(new ClassMapping<Cipher>().AddAllPropertiesAsColumns());
|
||||
var dataTable = BuildCiphersTable(ciphers);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
|
||||
@ -209,12 +207,7 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
UPDATE
|
||||
[dbo].[Cipher]
|
||||
SET
|
||||
-- Do not update [UserId]
|
||||
-- Do not update [FolderId]
|
||||
-- Do not update [Type]
|
||||
-- Do not update [Favorite]
|
||||
[Data] = TC.[Data],
|
||||
-- Do not update [CreationDate]
|
||||
[RevisionDate] = TC.[RevisionDate]
|
||||
FROM
|
||||
[dbo].[Cipher] C
|
||||
@ -244,19 +237,14 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task CreateAsync(IEnumerable<Cipher> ciphers)
|
||||
public Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Favorite> favorites, IEnumerable<Folder> folders,
|
||||
IEnumerable<FolderCipher> folderCiphers)
|
||||
{
|
||||
if(ciphers.Count() == 0)
|
||||
if(!ciphers.Any())
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
// Generate new Ids for these new ciphers
|
||||
foreach(var cipher in ciphers)
|
||||
{
|
||||
cipher.SetNewId();
|
||||
}
|
||||
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
connection.Open();
|
||||
@ -265,13 +253,47 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
{
|
||||
try
|
||||
{
|
||||
using(var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
||||
if(folders.Any())
|
||||
{
|
||||
using(var bulkCopy = new SqlBulkCopy(connection,
|
||||
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "[dbo].[Folder]";
|
||||
var dataTable = BuildFoldersTable(folders);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
}
|
||||
|
||||
using(var bulkCopy = new SqlBulkCopy(connection,
|
||||
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "[dbo].[Cipher]";
|
||||
var dataTable = ciphers.ToTable(new ClassMapping<Cipher>().AddAllPropertiesAsColumns());
|
||||
var dataTable = BuildCiphersTable(ciphers);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
|
||||
if(folderCiphers.Any())
|
||||
{
|
||||
using(var bulkCopy = new SqlBulkCopy(connection,
|
||||
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "[dbo].[FolderCipher]";
|
||||
var dataTable = BuildFolderCiphersTable(folderCiphers);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
}
|
||||
|
||||
if(favorites.Any())
|
||||
{
|
||||
using(var bulkCopy = new SqlBulkCopy(connection,
|
||||
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "[dbo].[Favorite]";
|
||||
var dataTable = BuildFavoritesTable(favorites);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
@ -285,6 +307,160 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private DataTable BuildCiphersTable(IEnumerable<Cipher> ciphers)
|
||||
{
|
||||
var c = ciphers.FirstOrDefault();
|
||||
if(c == null)
|
||||
{
|
||||
throw new ApplicationException("Must have some ciphers to bulk import.");
|
||||
}
|
||||
|
||||
var ciphersTable = new DataTable("CipherDataTable");
|
||||
|
||||
var idColumn = new DataColumn(nameof(c.Id), c.Id.GetType());
|
||||
ciphersTable.Columns.Add(idColumn);
|
||||
var userIdColumn = new DataColumn(nameof(c.UserId), typeof(Guid));
|
||||
ciphersTable.Columns.Add(userIdColumn);
|
||||
var organizationId = new DataColumn(nameof(c.OrganizationId), typeof(Guid));
|
||||
ciphersTable.Columns.Add(organizationId);
|
||||
var typeColumn = new DataColumn(nameof(c.Type), typeof(short));
|
||||
ciphersTable.Columns.Add(typeColumn);
|
||||
var dataColumn = new DataColumn(nameof(c.Data), typeof(string));
|
||||
ciphersTable.Columns.Add(dataColumn);
|
||||
var creationDateColumn = new DataColumn(nameof(c.CreationDate), c.CreationDate.GetType());
|
||||
ciphersTable.Columns.Add(creationDateColumn);
|
||||
var revisionDateColumn = new DataColumn(nameof(c.RevisionDate), c.RevisionDate.GetType());
|
||||
ciphersTable.Columns.Add(revisionDateColumn);
|
||||
|
||||
var keys = new DataColumn[1];
|
||||
keys[0] = idColumn;
|
||||
ciphersTable.PrimaryKey = keys;
|
||||
|
||||
foreach(var cipher in ciphers)
|
||||
{
|
||||
var row = ciphersTable.NewRow();
|
||||
|
||||
row[idColumn] = cipher.Id;
|
||||
row[userIdColumn] = cipher.UserId.HasValue ? (object)cipher.UserId.Value : DBNull.Value;
|
||||
row[organizationId] = cipher.OrganizationId.HasValue ? (object)cipher.OrganizationId.Value : DBNull.Value;
|
||||
row[typeColumn] = (short)cipher.Type;
|
||||
row[dataColumn] = cipher.Data;
|
||||
row[creationDateColumn] = cipher.CreationDate;
|
||||
row[revisionDateColumn] = cipher.RevisionDate;
|
||||
|
||||
ciphersTable.Rows.Add(row);
|
||||
}
|
||||
|
||||
return ciphersTable;
|
||||
}
|
||||
|
||||
private DataTable BuildFavoritesTable(IEnumerable<Favorite> favorites)
|
||||
{
|
||||
var f = favorites.FirstOrDefault();
|
||||
if(f == null)
|
||||
{
|
||||
throw new ApplicationException("Must have some favorites to bulk import.");
|
||||
}
|
||||
|
||||
var favoritesTable = new DataTable("FavoriteDataTable");
|
||||
|
||||
var userIdColumn = new DataColumn(nameof(f.UserId), f.UserId.GetType());
|
||||
favoritesTable.Columns.Add(userIdColumn);
|
||||
var cipherIdColumn = new DataColumn(nameof(f.CipherId), f.CipherId.GetType());
|
||||
favoritesTable.Columns.Add(cipherIdColumn);
|
||||
|
||||
var keys = new DataColumn[2];
|
||||
keys[0] = userIdColumn;
|
||||
keys[1] = cipherIdColumn;
|
||||
favoritesTable.PrimaryKey = keys;
|
||||
|
||||
foreach(var favorite in favorites)
|
||||
{
|
||||
var row = favoritesTable.NewRow();
|
||||
|
||||
row[cipherIdColumn] = favorite.CipherId;
|
||||
row[userIdColumn] = favorite.UserId;
|
||||
|
||||
favoritesTable.Rows.Add(row);
|
||||
}
|
||||
|
||||
return favoritesTable;
|
||||
}
|
||||
|
||||
private DataTable BuildFolderCiphersTable(IEnumerable<FolderCipher> folderCiphers)
|
||||
{
|
||||
var f = folderCiphers.FirstOrDefault();
|
||||
if(f == null)
|
||||
{
|
||||
throw new ApplicationException("Must have some folderCiphers to bulk import.");
|
||||
}
|
||||
|
||||
var folderCiphersTable = new DataTable("FolderCipherDataTable");
|
||||
|
||||
var folderIdColumn = new DataColumn(nameof(f.FolderId), f.FolderId.GetType());
|
||||
folderCiphersTable.Columns.Add(folderIdColumn);
|
||||
var cipherIdColumn = new DataColumn(nameof(f.CipherId), f.CipherId.GetType());
|
||||
folderCiphersTable.Columns.Add(cipherIdColumn);
|
||||
|
||||
var keys = new DataColumn[2];
|
||||
keys[0] = folderIdColumn;
|
||||
keys[1] = cipherIdColumn;
|
||||
folderCiphersTable.PrimaryKey = keys;
|
||||
|
||||
foreach(var folderCipher in folderCiphers)
|
||||
{
|
||||
var row = folderCiphersTable.NewRow();
|
||||
|
||||
row[folderIdColumn] = folderCipher.FolderId;
|
||||
row[cipherIdColumn] = folderCipher.CipherId;
|
||||
|
||||
folderCiphersTable.Rows.Add(row);
|
||||
}
|
||||
|
||||
return folderCiphersTable;
|
||||
}
|
||||
|
||||
private DataTable BuildFoldersTable(IEnumerable<Folder> folders)
|
||||
{
|
||||
var f = folders.FirstOrDefault();
|
||||
if(f == null)
|
||||
{
|
||||
throw new ApplicationException("Must have some folders to bulk import.");
|
||||
}
|
||||
|
||||
var foldersTable = new DataTable("FolderDataTable");
|
||||
|
||||
var idColumn = new DataColumn(nameof(f.Id), f.Id.GetType());
|
||||
foldersTable.Columns.Add(idColumn);
|
||||
var userIdColumn = new DataColumn(nameof(f.UserId), f.UserId.GetType());
|
||||
foldersTable.Columns.Add(userIdColumn);
|
||||
var nameColumn = new DataColumn(nameof(f.Name), typeof(string));
|
||||
foldersTable.Columns.Add(nameColumn);
|
||||
var creationDateColumn = new DataColumn(nameof(f.CreationDate), f.CreationDate.GetType());
|
||||
foldersTable.Columns.Add(creationDateColumn);
|
||||
var revisionDateColumn = new DataColumn(nameof(f.RevisionDate), f.RevisionDate.GetType());
|
||||
foldersTable.Columns.Add(revisionDateColumn);
|
||||
|
||||
var keys = new DataColumn[1];
|
||||
keys[0] = idColumn;
|
||||
foldersTable.PrimaryKey = keys;
|
||||
|
||||
foreach(var folder in folders)
|
||||
{
|
||||
var row = foldersTable.NewRow();
|
||||
|
||||
row[idColumn] = folder.Id;
|
||||
row[userIdColumn] = folder.UserId;
|
||||
row[nameColumn] = folder.Name;
|
||||
row[creationDateColumn] = folder.CreationDate;
|
||||
row[revisionDateColumn] = folder.RevisionDate;
|
||||
|
||||
foldersTable.Rows.Add(row);
|
||||
}
|
||||
|
||||
return foldersTable;
|
||||
}
|
||||
|
||||
public class CipherWithSubvaults : Cipher
|
||||
{
|
||||
public DataTable SubvaultIds { get; set; }
|
||||
|
@ -186,15 +186,30 @@ namespace Bit.Core.Services
|
||||
List<CipherDetails> ciphers,
|
||||
IEnumerable<KeyValuePair<int, int>> folderRelationships)
|
||||
{
|
||||
// create all the folders
|
||||
var folderTasks = new List<Task>();
|
||||
// Init. ids and build out favorites.
|
||||
var favorites = new List<Favorite>();
|
||||
foreach(var cipher in ciphers)
|
||||
{
|
||||
cipher.SetNewId();
|
||||
|
||||
if(cipher.UserId.HasValue && cipher.Favorite)
|
||||
{
|
||||
favorites.Add(new Favorite
|
||||
{
|
||||
UserId = cipher.UserId.Value,
|
||||
CipherId = cipher.Id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Init. ids for folders
|
||||
foreach(var folder in folders)
|
||||
{
|
||||
folderTasks.Add(_folderRepository.CreateAsync(folder));
|
||||
folder.SetNewId();
|
||||
}
|
||||
await Task.WhenAll(folderTasks);
|
||||
|
||||
// associate the newly created folders to the ciphers
|
||||
// Create the folder associations based on the newly created folder ids
|
||||
var folderCiphers = new List<FolderCipher>();
|
||||
foreach(var relationship in folderRelationships)
|
||||
{
|
||||
var cipher = ciphers.ElementAtOrDefault(relationship.Key);
|
||||
@ -205,11 +220,15 @@ namespace Bit.Core.Services
|
||||
continue;
|
||||
}
|
||||
|
||||
//cipher.FolderId = folder.Id;
|
||||
folderCiphers.Add(new FolderCipher
|
||||
{
|
||||
FolderId = folder.Id,
|
||||
CipherId = cipher.Id
|
||||
});
|
||||
}
|
||||
|
||||
// create all the ciphers
|
||||
await _cipherRepository.CreateAsync(ciphers);
|
||||
// Create it all
|
||||
await _cipherRepository.CreateAsync(ciphers, favorites, folders, folderCiphers);
|
||||
|
||||
// push
|
||||
var userId = folders.FirstOrDefault()?.UserId ?? ciphers.FirstOrDefault()?.UserId;
|
||||
|
Loading…
Reference in New Issue
Block a user