Add TSGroupModelBuilder.
This commit is contained in:
parent
fe692fc281
commit
c572db4886
@ -35,12 +35,11 @@ public extension UpdateGroupViewController {
|
||||
newAvatarData: Data?,
|
||||
v1Members: Set<SignalServiceAddress>) -> TSGroupModel {
|
||||
do {
|
||||
let groupId = oldGroupModel.groupId
|
||||
return try databaseStorage.read { transaction in
|
||||
let groupMembership: GroupMembership
|
||||
let newGroupMembership: GroupMembership
|
||||
switch oldGroupModel.groupsVersion {
|
||||
case .V1:
|
||||
groupMembership = GroupMembership(v1Members: v1Members)
|
||||
newGroupMembership = GroupMembership(v1Members: v1Members)
|
||||
case .V2:
|
||||
// GroupsV2 TODO: This is a temporary implementation until we
|
||||
// rewrite groups v2 to be aware of roles, access, kicking
|
||||
@ -59,19 +58,14 @@ public extension UpdateGroupViewController {
|
||||
}
|
||||
// GroupsV2 TODO: Remove members, change roles, etc. when
|
||||
// UI supports pending members, kicking members, etc..
|
||||
groupMembership = groupMembershipBuilder.build()
|
||||
newGroupMembership = groupMembershipBuilder.build()
|
||||
}
|
||||
let groupsVersion = oldGroupModel.groupsVersion
|
||||
return try GroupManager.buildGroupModel(groupId: groupId,
|
||||
name: newTitle,
|
||||
avatarData: newAvatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: oldGroupModel.groupAccess,
|
||||
groupsVersion: groupsVersion,
|
||||
groupV2Revision: oldGroupModel.groupV2Revision,
|
||||
groupSecretParamsData: oldGroupModel.groupSecretParamsData,
|
||||
newGroupSeed: nil,
|
||||
transaction: transaction)
|
||||
|
||||
var builder = oldGroupModel.asBuilder
|
||||
builder.name = newTitle
|
||||
builder.avatarData = newAvatarData
|
||||
builder.groupMembership = newGroupMembership
|
||||
return try builder.build(transaction: transaction)
|
||||
}
|
||||
} catch {
|
||||
owsFailDebug("Error: \(error)")
|
||||
|
||||
@ -458,8 +458,8 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
|
||||
}
|
||||
}
|
||||
let oldGroupModel = groupThread.groupModel
|
||||
let newGroupModel = try GroupManager.buildGroupModel(groupV2Snapshot: groupChange.snapshot,
|
||||
transaction: transaction)
|
||||
let builder = try TSGroupModelBuilder(groupV2Snapshot: groupChange.snapshot)
|
||||
let newGroupModel = try builder.build(transaction: transaction)
|
||||
|
||||
if changeRevision == oldGroupModel.groupV2Revision {
|
||||
if !oldGroupModel.isEqual(to: newGroupModel) {
|
||||
@ -536,8 +536,8 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
|
||||
}
|
||||
|
||||
return databaseStorage.write(.promise) { (transaction: SDSAnyWriteTransaction) throws -> TSGroupThread in
|
||||
let newGroupModel = try GroupManager.buildGroupModel(groupV2Snapshot: groupV2Snapshot,
|
||||
transaction: transaction)
|
||||
let builder = try TSGroupModelBuilder(groupV2Snapshot: groupV2Snapshot)
|
||||
let newGroupModel = try builder.build(transaction: transaction)
|
||||
let newDisappearingMessageToken = groupV2Snapshot.disappearingMessageToken
|
||||
// groupUpdateSourceAddress is nil because we don't know the
|
||||
// author(s) of changes reflected in the snapshot.
|
||||
|
||||
@ -51,7 +51,6 @@ public class GroupsV2Changes {
|
||||
changeActionsProto: GroupsProtoGroupChangeActions,
|
||||
transaction: SDSAnyReadTransaction) throws -> ChangedGroupModel {
|
||||
let oldGroupModel = groupThread.groupModel
|
||||
let groupId = oldGroupModel.groupId
|
||||
let groupsVersion = oldGroupModel.groupsVersion
|
||||
guard groupsVersion == .V2 else {
|
||||
throw OWSAssertionError("Invalid groupsVersion: \(groupsVersion).")
|
||||
@ -261,7 +260,6 @@ public class GroupsV2Changes {
|
||||
if let disappearingMessagesTimerEncrypted = action.timer {
|
||||
let disappearingMessagesTimerDecrypted = try groupV2Params.decryptBlob(disappearingMessagesTimerEncrypted)
|
||||
let disappearingMessagesProto = try GroupsProtoDisappearingMessagesTimer.parseData(disappearingMessagesTimerDecrypted)
|
||||
let durationSeconds = disappearingMessagesProto.duration
|
||||
newDisappearingMessageToken = DisappearingMessageToken.token(forProtoExpireTimer: disappearingMessagesProto.duration)
|
||||
}
|
||||
}
|
||||
@ -283,17 +281,18 @@ public class GroupsV2Changes {
|
||||
let newGroupMembership = groupMembershipBuilder.build()
|
||||
let newGroupAccess = GroupAccess(members: newMembersAccess, attributes: newAttributesAccess)
|
||||
// GroupsV2 TODO: Avatar.
|
||||
let avatarData: Data? = oldGroupModel.groupAvatarData
|
||||
let newAvatarData: Data? = oldGroupModel.groupAvatarData
|
||||
|
||||
var builder = oldGroupModel.asBuilder
|
||||
builder.name = newGroupName
|
||||
builder.avatarData = newAvatarData
|
||||
builder.groupMembership = newGroupMembership
|
||||
builder.groupAccess = newGroupAccess
|
||||
builder.groupsVersion = groupsVersion
|
||||
builder.groupV2Revision = newRevision
|
||||
builder.groupSecretParamsData = groupSecretParamsData
|
||||
let newGroupModel = try builder.build(transaction: transaction)
|
||||
|
||||
let newGroupModel = try GroupManager.buildGroupModel(groupId: groupId,
|
||||
name: newGroupName,
|
||||
avatarData: avatarData,
|
||||
groupMembership: newGroupMembership,
|
||||
groupAccess: newGroupAccess,
|
||||
groupsVersion: groupsVersion,
|
||||
groupV2Revision: newRevision,
|
||||
groupSecretParamsData: groupSecretParamsData,
|
||||
transaction: transaction)
|
||||
return ChangedGroupModel(oldGroupModel: oldGroupModel,
|
||||
newGroupModel: newGroupModel,
|
||||
newDisappearingMessageToken: newDisappearingMessageToken,
|
||||
|
||||
@ -75,7 +75,7 @@ public class GroupsV2Test: NSObject {
|
||||
}
|
||||
}.map(on: .global()) { (groupId: Data, groupV2Snapshot: GroupV2Snapshot) throws -> Data in
|
||||
let groupModel = try self.databaseStorage.read { transaction in
|
||||
return try GroupManager.buildGroupModel(groupV2Snapshot: groupV2Snapshot, transaction: transaction)
|
||||
return try TSGroupModelBuilder(groupV2Snapshot: groupV2Snapshot).build(transaction: transaction)
|
||||
}
|
||||
guard groupModel.groupV2Revision == 0 else {
|
||||
throw OWSAssertionError("Unexpected groupV2Revision: \(groupModel.groupV2Revision).")
|
||||
@ -145,7 +145,7 @@ public class GroupsV2Test: NSObject {
|
||||
}
|
||||
}.map(on: .global()) { (groupId: Data, groupV2Snapshot: GroupV2Snapshot) throws -> Data in
|
||||
let groupModel = try self.databaseStorage.read { transaction in
|
||||
return try GroupManager.buildGroupModel(groupV2Snapshot: groupV2Snapshot, transaction: transaction)
|
||||
return try TSGroupModelBuilder(groupV2Snapshot: groupV2Snapshot).build(transaction: transaction)
|
||||
}
|
||||
guard groupModel.groupV2Revision == 1 else {
|
||||
throw OWSAssertionError("Unexpected groupV2Revision: \(groupModel.groupV2Revision).")
|
||||
@ -215,7 +215,7 @@ public class GroupsV2Test: NSObject {
|
||||
}
|
||||
}.map(on: .global()) { (groupId: Data, groupV2Snapshot: GroupV2Snapshot) throws -> Data in
|
||||
let groupModel = try self.databaseStorage.read { transaction in
|
||||
return try GroupManager.buildGroupModel(groupV2Snapshot: groupV2Snapshot, transaction: transaction)
|
||||
return try TSGroupModelBuilder(groupV2Snapshot: groupV2Snapshot).build(transaction: transaction)
|
||||
}
|
||||
guard groupModel.groupV2Revision == 2 else {
|
||||
throw OWSAssertionError("Unexpected groupV2Revision: \(groupModel.groupV2Revision).")
|
||||
|
||||
@ -102,148 +102,23 @@ public class GroupManager: NSObject {
|
||||
|
||||
// MARK: - Group Models
|
||||
|
||||
public static func buildGroupModel(groupId groupIdParam: Data?,
|
||||
name nameParam: String?,
|
||||
avatarData: Data?,
|
||||
groupMembership: GroupMembership,
|
||||
groupAccess: GroupAccess,
|
||||
groupsVersion groupsVersionParam: GroupsVersion? = nil,
|
||||
groupV2Revision: UInt32,
|
||||
groupSecretParamsData groupSecretParamsDataParam: Data? = nil,
|
||||
newGroupSeed newGroupSeedParam: NewGroupSeed? = nil,
|
||||
transaction: SDSAnyReadTransaction) throws -> TSGroupModel {
|
||||
|
||||
let newGroupSeed: NewGroupSeed
|
||||
if let newGroupSeedParam = newGroupSeedParam {
|
||||
newGroupSeed = newGroupSeedParam
|
||||
} else {
|
||||
newGroupSeed = NewGroupSeed()
|
||||
}
|
||||
|
||||
let allUsers = groupMembership.allUsers
|
||||
for recipientAddress in allUsers {
|
||||
guard recipientAddress.isValid else {
|
||||
throw OWSAssertionError("Invalid address.")
|
||||
}
|
||||
}
|
||||
var name: String?
|
||||
if let strippedName = nameParam?.stripped,
|
||||
strippedName.count > 0 {
|
||||
name = strippedName
|
||||
}
|
||||
|
||||
let groupsVersion: GroupsVersion
|
||||
if let groupsVersionParam = groupsVersionParam {
|
||||
groupsVersion = groupsVersionParam
|
||||
} else {
|
||||
groupsVersion = self.groupsVersion(for: allUsers,
|
||||
transaction: transaction)
|
||||
}
|
||||
|
||||
let groupId: Data
|
||||
if let groupIdParam = groupIdParam {
|
||||
groupId = groupIdParam
|
||||
} else {
|
||||
switch groupsVersion {
|
||||
case .V1:
|
||||
groupId = newGroupSeed.groupIdV1
|
||||
case .V2:
|
||||
guard let groupIdV2 = newGroupSeed.groupIdV2 else {
|
||||
throw OWSAssertionError("Missing groupIdV2.")
|
||||
}
|
||||
groupId = groupIdV2
|
||||
}
|
||||
}
|
||||
guard isValidGroupId(groupId, groupsVersion: groupsVersion) else {
|
||||
throw OWSAssertionError("Invalid groupId.")
|
||||
}
|
||||
|
||||
switch groupsVersion {
|
||||
case .V1:
|
||||
return TSGroupModel(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
members: Array(groupMembership.nonPendingMembers))
|
||||
case .V2:
|
||||
let groupSecretParamsData: Data
|
||||
if let groupSecretParamsDataParam = groupSecretParamsDataParam {
|
||||
groupSecretParamsData = groupSecretParamsDataParam
|
||||
} else {
|
||||
guard let groupSecretParamsDataParam = newGroupSeed.groupSecretParamsData else {
|
||||
throw OWSAssertionError("Missing groupSecretParamsData.")
|
||||
}
|
||||
groupSecretParamsData = groupSecretParamsDataParam
|
||||
}
|
||||
|
||||
return TSGroupModelV2(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
revision: groupV2Revision,
|
||||
secretParamsData: groupSecretParamsData)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a group state proto received from the service
|
||||
// into a group model.
|
||||
public static func buildGroupModel(groupV2Snapshot: GroupV2Snapshot,
|
||||
transaction: SDSAnyReadTransaction) throws -> TSGroupModel {
|
||||
let groupSecretParamsData = groupV2Snapshot.groupSecretParamsData
|
||||
let groupId = try groupsV2.groupId(forGroupSecretParamsData: groupSecretParamsData)
|
||||
let name: String = groupV2Snapshot.title
|
||||
let groupMembership = groupV2Snapshot.groupMembership
|
||||
let groupAccess = groupV2Snapshot.groupAccess
|
||||
// GroupsV2 TODO: Avatar.
|
||||
let avatarData: Data? = nil
|
||||
let groupsVersion = GroupsVersion.V2
|
||||
let revision = groupV2Snapshot.revision
|
||||
|
||||
return try buildGroupModel(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupsVersion: groupsVersion,
|
||||
groupV2Revision: revision,
|
||||
groupSecretParamsData: groupSecretParamsData,
|
||||
transaction: transaction)
|
||||
}
|
||||
|
||||
// This should only be used for certain legacy edge cases.
|
||||
@objc
|
||||
public static func fakeGroupModel(groupId: Data?,
|
||||
transaction: SDSAnyReadTransaction) -> TSGroupModel? {
|
||||
do {
|
||||
let groupMembership = GroupMembership.empty
|
||||
let groupAccess = GroupAccess.allAccess
|
||||
return try buildGroupModel(groupId: groupId,
|
||||
name: nil,
|
||||
avatarData: nil,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupsVersion: .V1,
|
||||
groupV2Revision: 0,
|
||||
groupSecretParamsData: nil,
|
||||
transaction: transaction)
|
||||
var builder = TSGroupModelBuilder()
|
||||
builder.groupId = groupId
|
||||
builder.groupsVersion = .V1
|
||||
return try builder.build(transaction: transaction)
|
||||
} catch {
|
||||
owsFailDebug("Error: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private static func groupsVersion(for members: Set<SignalServiceAddress>,
|
||||
transaction: SDSAnyReadTransaction) -> GroupsVersion {
|
||||
|
||||
guard RemoteConfig.groupsV2CreateGroups else {
|
||||
return .V1
|
||||
}
|
||||
let canUseV2 = self.canUseV2(for: members, transaction: transaction)
|
||||
return canUseV2 ? defaultGroupsVersion : .V1
|
||||
}
|
||||
|
||||
private static func canUseV2(for members: Set<SignalServiceAddress>,
|
||||
transaction: SDSAnyReadTransaction) -> Bool {
|
||||
public static func canUseV2(for members: Set<SignalServiceAddress>,
|
||||
transaction: SDSAnyReadTransaction) -> Bool {
|
||||
|
||||
for recipientAddress in members {
|
||||
guard doesUserSupportGroupsV2(address: recipientAddress, transaction: transaction) else {
|
||||
@ -363,14 +238,14 @@ public class GroupManager: NSObject {
|
||||
throw OWSAssertionError("Missing localAddress.")
|
||||
}
|
||||
|
||||
return try self.buildGroupModel(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupV2Revision: 0,
|
||||
newGroupSeed: newGroupSeed,
|
||||
transaction: transaction)
|
||||
var builder = TSGroupModelBuilder()
|
||||
builder.groupId = groupId
|
||||
builder.name = name
|
||||
builder.avatarData = avatarData
|
||||
builder.groupMembership = groupMembership
|
||||
builder.groupAccess = groupAccess
|
||||
builder.newGroupSeed = newGroupSeed
|
||||
return try builder.build(transaction: transaction)
|
||||
}
|
||||
return groupModel
|
||||
}.then(on: .global()) { (proposedGroupModel: TSGroupModel) -> Promise<TSGroupModel> in
|
||||
@ -384,7 +259,7 @@ public class GroupManager: NSObject {
|
||||
self.groupsV2.fetchCurrentGroupV2Snapshot(groupModel: proposedGroupModel)
|
||||
}.map(on: .global()) { (groupV2Snapshot: GroupV2Snapshot) -> TSGroupModel in
|
||||
let createdGroupModel = try self.databaseStorage.read { transaction in
|
||||
return try self.buildGroupModel(groupV2Snapshot: groupV2Snapshot, transaction: transaction)
|
||||
return try TSGroupModelBuilder(groupV2Snapshot: groupV2Snapshot).build(transaction: transaction)
|
||||
}
|
||||
if proposedGroupModel != createdGroupModel {
|
||||
Logger.verbose("proposedGroupModel: \(proposedGroupModel.debugDescription)")
|
||||
@ -592,14 +467,15 @@ public class GroupManager: NSObject {
|
||||
// GroupsV2 TODO: Let tests specify access levels.
|
||||
let groupAccess = GroupAccess.allAccess
|
||||
// Use buildGroupModel() to fill in defaults, like it was a new group.
|
||||
let groupModel = try buildGroupModel(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupsVersion: groupsVersion,
|
||||
groupV2Revision: 0,
|
||||
transaction: transaction)
|
||||
|
||||
var builder = TSGroupModelBuilder()
|
||||
builder.groupId = groupId
|
||||
builder.name = name
|
||||
builder.avatarData = avatarData
|
||||
builder.groupMembership = groupMembership
|
||||
builder.groupAccess = groupAccess
|
||||
builder.groupsVersion = groupsVersion
|
||||
let groupModel = try builder.build(transaction: transaction)
|
||||
|
||||
// Just create it in the database, don't create it on the service.
|
||||
//
|
||||
@ -654,15 +530,16 @@ public class GroupManager: NSObject {
|
||||
groupUpdateSourceAddress: SignalServiceAddress?,
|
||||
transaction: SDSAnyWriteTransaction) throws -> UpsertGroupResult {
|
||||
|
||||
let groupModel = try buildGroupModel(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupsVersion: groupsVersion,
|
||||
groupV2Revision: groupV2Revision,
|
||||
groupSecretParamsData: groupSecretParamsData,
|
||||
transaction: transaction)
|
||||
var builder = TSGroupModelBuilder()
|
||||
builder.groupId = groupId
|
||||
builder.name = name
|
||||
builder.avatarData = avatarData
|
||||
builder.groupMembership = groupMembership
|
||||
builder.groupAccess = groupAccess
|
||||
builder.groupsVersion = groupsVersion
|
||||
builder.groupV2Revision = groupV2Revision
|
||||
builder.groupSecretParamsData = groupSecretParamsData
|
||||
let groupModel = try builder.build(transaction: transaction)
|
||||
|
||||
return try remoteUpsertExistingGroup(groupModel: groupModel,
|
||||
disappearingMessageToken: disappearingMessageToken,
|
||||
@ -898,15 +775,16 @@ public class GroupManager: NSObject {
|
||||
// since we'll probably be updating the TSGroupThread's
|
||||
// group models with one derived from the service.
|
||||
let newRevision = oldGroupModel.groupV2Revision + 1
|
||||
let newGroupModel = try buildGroupModel(groupId: oldGroupModel.groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupsVersion: oldGroupModel.groupsVersion,
|
||||
groupV2Revision: newRevision,
|
||||
groupSecretParamsData: oldGroupModel.groupSecretParamsData,
|
||||
transaction: transaction)
|
||||
var builder = TSGroupModelBuilder()
|
||||
builder.groupId = oldGroupModel.groupId
|
||||
builder.name = name
|
||||
builder.avatarData = avatarData
|
||||
builder.groupMembership = groupMembership
|
||||
builder.groupAccess = groupAccess
|
||||
builder.groupsVersion = oldGroupModel.groupsVersion
|
||||
builder.groupV2Revision = newRevision
|
||||
builder.groupSecretParamsData = oldGroupModel.groupSecretParamsData
|
||||
let newGroupModel = try builder.build(transaction: transaction)
|
||||
if oldGroupModel.isEqual(to: newGroupModel) {
|
||||
// Skip redundant update.
|
||||
throw GroupsV2Error.redundantChange
|
||||
@ -1028,8 +906,8 @@ public class GroupManager: NSObject {
|
||||
}
|
||||
|
||||
private static func sendDisappearingMessagesConfigurationMessage(updateResult: UpdateDMConfigurationResult,
|
||||
thread: TSThread,
|
||||
transaction: SDSAnyWriteTransaction) {
|
||||
thread: TSThread,
|
||||
transaction: SDSAnyWriteTransaction) {
|
||||
guard updateResult.action == .updated else {
|
||||
// The update was redundant, don't send an update message.
|
||||
return
|
||||
@ -1090,17 +968,11 @@ public class GroupManager: NSObject {
|
||||
var groupMembershipBuilder = oldGroupModel.groupMembership.asBuilder
|
||||
groupMembershipBuilder.remove(localAddress)
|
||||
let newGroupMembership = groupMembershipBuilder.build()
|
||||
let groupAccess = oldGroupModel.groupAccess
|
||||
let newGroupModel = try self.buildGroupModel(groupId: groupId,
|
||||
name: oldGroupModel.groupName,
|
||||
avatarData: oldGroupModel.groupAvatarData,
|
||||
groupMembership: newGroupMembership,
|
||||
groupAccess: groupAccess,
|
||||
groupsVersion: oldGroupModel.groupsVersion,
|
||||
groupV2Revision: oldGroupModel.groupV2Revision,
|
||||
groupSecretParamsData: nil,
|
||||
newGroupSeed: nil,
|
||||
transaction: transaction)
|
||||
|
||||
var builder = oldGroupModel.asBuilder
|
||||
builder.groupMembership = newGroupMembership
|
||||
let newGroupModel = try builder.build(transaction: transaction)
|
||||
|
||||
let groupUpdateSourceAddress = localAddress
|
||||
let result = try self.updateExistingGroupThreadInDatabaseAndCreateInfoMessage(newGroupModel: newGroupModel,
|
||||
newDisappearingMessageToken: nil,
|
||||
|
||||
@ -19,10 +19,10 @@ typedef NS_CLOSED_ENUM(uint32_t, GroupsVersion) { GroupsVersionV1 = 0, GroupsVer
|
||||
typedef NS_CLOSED_ENUM(
|
||||
NSUInteger, TSGroupMemberRole) { TSGroupMemberRole_Normal = 0, TSGroupMemberRole_Administrator = 1 };
|
||||
|
||||
// NOTE: This class is tightly coupled to GroupManager.
|
||||
// NOTE: This class is tightly coupled to TSGroupModelBuilder.
|
||||
// If you modify this class - especially if you
|
||||
// add any new properties - make sure to update
|
||||
// GroupManager.buildGroupModel().
|
||||
// TSGroupModelBuilder.
|
||||
@interface TSGroupModel : MTLModel
|
||||
|
||||
// groupMembers includes administrators and normal members.
|
||||
|
||||
@ -21,10 +21,10 @@ public extension TSGroupModel {
|
||||
|
||||
// Like TSGroupModel, TSGroupModelV2 is intended to be immutable.
|
||||
//
|
||||
// NOTE: This class is tightly coupled to GroupManager.
|
||||
// NOTE: This class is tightly coupled to TSGroupModelBuilder.
|
||||
// If you modify this class - especially if you
|
||||
// add any new properties - make sure to update
|
||||
// GroupManager.buildGroupModel().
|
||||
// TSGroupModelBuilder.
|
||||
@objc
|
||||
public class TSGroupModelV2: TSGroupModel {
|
||||
|
||||
|
||||
160
SignalServiceKit/src/groups/TSGroupModelBuilder.swift
Normal file
160
SignalServiceKit/src/groups/TSGroupModelBuilder.swift
Normal file
@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct TSGroupModelBuilder {
|
||||
|
||||
// MARK: - Dependencies
|
||||
|
||||
private var groupsV2: GroupsV2 {
|
||||
return SSKEnvironment.shared.groupsV2
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public var groupId: Data?
|
||||
public var name: String?
|
||||
public var avatarData: Data?
|
||||
public var groupMembership = GroupMembership()
|
||||
public var groupAccess: GroupAccess?
|
||||
public var groupsVersion: GroupsVersion?
|
||||
public var groupV2Revision: UInt32 = 0
|
||||
public var groupSecretParamsData: Data?
|
||||
public var newGroupSeed: NewGroupSeed?
|
||||
|
||||
public init() {}
|
||||
|
||||
// Convert a group state proto received from the service
|
||||
// into a group model.
|
||||
public init(groupV2Snapshot: GroupV2Snapshot) throws {
|
||||
self.groupId = try groupsV2.groupId(forGroupSecretParamsData: groupV2Snapshot.groupSecretParamsData)
|
||||
self.name = groupV2Snapshot.title
|
||||
// GroupsV2 TODO: Avatar.
|
||||
// self.avatarData = groupV2Snapshot.avatarData
|
||||
self.groupMembership = groupV2Snapshot.groupMembership
|
||||
self.groupAccess = groupV2Snapshot.groupAccess
|
||||
self.groupsVersion = GroupsVersion.V2
|
||||
self.groupV2Revision = groupV2Snapshot.revision
|
||||
self.groupSecretParamsData = groupV2Snapshot.groupSecretParamsData
|
||||
}
|
||||
|
||||
public func build(transaction: SDSAnyReadTransaction) throws -> TSGroupModel {
|
||||
|
||||
let allUsers = groupMembership.allUsers
|
||||
for recipientAddress in allUsers {
|
||||
guard recipientAddress.isValid else {
|
||||
throw OWSAssertionError("Invalid address.")
|
||||
}
|
||||
}
|
||||
|
||||
var name: String?
|
||||
if let strippedName = self.name?.stripped,
|
||||
strippedName.count > 0 {
|
||||
name = strippedName
|
||||
}
|
||||
|
||||
let groupsVersion = buildGroupsVersion(for: allUsers,
|
||||
transaction: transaction)
|
||||
|
||||
let newGroupSeed = self.newGroupSeed ?? NewGroupSeed()
|
||||
|
||||
let groupId = try buildGroupId(groupsVersion: groupsVersion,
|
||||
newGroupSeed: newGroupSeed)
|
||||
|
||||
guard GroupManager.isValidGroupId(groupId, groupsVersion: groupsVersion) else {
|
||||
throw OWSAssertionError("Invalid groupId.")
|
||||
}
|
||||
|
||||
switch groupsVersion {
|
||||
case .V1:
|
||||
return TSGroupModel(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
members: Array(groupMembership.nonPendingMembers))
|
||||
case .V2:
|
||||
let groupAccess = buildGroupAccess(groupsVersion: groupsVersion)
|
||||
let groupSecretParamsData = try buildGroupSecretParamsData(newGroupSeed: newGroupSeed)
|
||||
|
||||
return TSGroupModelV2(groupId: groupId,
|
||||
name: name,
|
||||
avatarData: avatarData,
|
||||
groupMembership: groupMembership,
|
||||
groupAccess: groupAccess,
|
||||
revision: groupV2Revision,
|
||||
secretParamsData: groupSecretParamsData)
|
||||
}
|
||||
}
|
||||
|
||||
private func buildGroupId(groupsVersion: GroupsVersion,
|
||||
newGroupSeed: NewGroupSeed) throws -> Data {
|
||||
if let value = groupId {
|
||||
return value
|
||||
}
|
||||
|
||||
switch groupsVersion {
|
||||
case .V1:
|
||||
return newGroupSeed.groupIdV1
|
||||
case .V2:
|
||||
guard let groupIdV2 = newGroupSeed.groupIdV2 else {
|
||||
throw OWSAssertionError("Missing groupIdV2.")
|
||||
}
|
||||
return groupIdV2
|
||||
}
|
||||
}
|
||||
|
||||
private func buildGroupSecretParamsData(newGroupSeed: NewGroupSeed) throws -> Data {
|
||||
if let value = groupSecretParamsData {
|
||||
return value
|
||||
}
|
||||
|
||||
guard let value = newGroupSeed.groupSecretParamsData else {
|
||||
throw OWSAssertionError("Missing groupSecretParamsData.")
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private func buildGroupAccess(groupsVersion: GroupsVersion) -> GroupAccess {
|
||||
if let value = groupAccess {
|
||||
return value
|
||||
}
|
||||
|
||||
switch groupsVersion {
|
||||
case .V1:
|
||||
return GroupAccess.forV1
|
||||
case .V2:
|
||||
return GroupAccess.defaultV2Access
|
||||
}
|
||||
}
|
||||
|
||||
private func buildGroupsVersion(for members: Set<SignalServiceAddress>,
|
||||
transaction: SDSAnyReadTransaction) -> GroupsVersion {
|
||||
if let value = groupsVersion {
|
||||
return value
|
||||
}
|
||||
|
||||
guard RemoteConfig.groupsV2CreateGroups else {
|
||||
return .V1
|
||||
}
|
||||
let canUseV2 = GroupManager.canUseV2(for: members, transaction: transaction)
|
||||
return canUseV2 ? GroupManager.defaultGroupsVersion : .V1
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public extension TSGroupModel {
|
||||
var asBuilder: TSGroupModelBuilder {
|
||||
var builder = TSGroupModelBuilder()
|
||||
builder.groupId = self.groupId
|
||||
builder.name = self.groupName
|
||||
builder.avatarData = self.groupAvatarData
|
||||
builder.groupMembership = self.groupMembership
|
||||
builder.groupAccess = self.groupAccess
|
||||
builder.groupsVersion = self.groupsVersion
|
||||
builder.groupV2Revision = self.groupV2Revision
|
||||
builder.groupSecretParamsData = self.groupSecretParamsData
|
||||
return builder
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user