From 50c2974e3d3db999d32c64199ecdcd25d2466f59 Mon Sep 17 00:00:00 2001 From: Dovchik Date: Wed, 17 Jan 2024 11:53:27 +0100 Subject: [PATCH] feat: implement merge --- src/Sinch/Conversation/Contacts/Contact.cs | 17 +++++++- src/Sinch/Conversation/Contacts/Contacts.cs | 43 ++++++++++++++++--- .../e2e/Conversation/ContactsTests.cs | 8 ++++ 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/Sinch/Conversation/Contacts/Contact.cs b/src/Sinch/Conversation/Contacts/Contact.cs index 5c40b67c..e66e4a79 100644 --- a/src/Sinch/Conversation/Contacts/Contact.cs +++ b/src/Sinch/Conversation/Contacts/Contact.cs @@ -6,10 +6,25 @@ namespace Sinch.Conversation.Contacts { public class Contact { + /// + /// Tracks the fields which where initialized. + /// + private readonly ISet _setFields = new HashSet(); + + private List _channelIdentities; + /// /// List of channel identities. /// - public List ChannelIdentities { get; set; } + public List ChannelIdentities + { + get => _channelIdentities; + set + { + _setFields.Add(nameof(ChannelIdentities)); + _channelIdentities = value; + } + } /// diff --git a/src/Sinch/Conversation/Contacts/Contacts.cs b/src/Sinch/Conversation/Contacts/Contacts.cs index 5af0e565..60e0561e 100644 --- a/src/Sinch/Conversation/Contacts/Contacts.cs +++ b/src/Sinch/Conversation/Contacts/Contacts.cs @@ -99,7 +99,10 @@ public interface ISinchConversationContacts Task Delete(string contactId, CancellationToken cancellationToken = default); /// - /// Get user profile from a specific channel. Only supported on MESSENGER, INSTAGRAM, VIBER and LINE channels. Note that, in order to retrieve a WhatsApp display name, you can use the Get a Contact or List Contacts operations, which will populate the display_name field of each returned contact with the WhatsApp display name (if the name is already stored on the server and the display_name field has not been overwritten by the user). + /// Get user profile from a specific channel. Only supported on MESSENGER, INSTAGRAM, VIBER and LINE channels. Note + /// that, in order to retrieve a WhatsApp display name, you can use the Get a Contact or List Contacts operations, + /// which will populate the display_name field of each returned contact with the WhatsApp display name (if the name is + /// already stored on the server and the display_name field has not been overwritten by the user). /// /// /// @@ -114,6 +117,21 @@ Task GetChannelProfile(GetChannelProfileRequest request, /// /// Task Update(Contact contact, CancellationToken cancellationToken = default); + + /// + /// Merge two contacts. The remaining contact will contain all conversations that the removed contact did. If both + /// contacts had conversations within the same App, messages from the removed contact will be merged into corresponding + /// active conversations in the destination contact. Channel identities will be moved from the source contact to the + /// destination contact only for channels that weren't present there before. Moved channel identities will be placed at + /// the bottom of the channel priority list. Optional fields from the source contact will be copied only if + /// corresponding fields in the destination contact are empty The contact being removed cannot be referenced after this + /// call. + /// + /// The unique ID of the contact that should be kept when merging two contacts. + /// The ID of the contact that should be removed. + /// + /// + Task Merge(string destinationId, string sourceId, CancellationToken cancellationToken = default); } internal class Contacts : ISinchConversationContacts @@ -170,7 +188,7 @@ public async IAsyncEnumerable ListAuto(ListContactsRequest request, var query = Utils.ToSnakeCaseQueryString(request); var uri = new Uri(_baseAddress, $"/v1/projects/{_projectId}/contacts?{query}"); var response = - await _http.Send(uri, HttpMethod.Get, cancellationToken: cancellationToken); + await _http.Send(uri, HttpMethod.Get, cancellationToken); request.PageToken = response.NextPageToken; foreach (var contact in response.Contacts) yield return contact; } while (request.PageToken is not null); @@ -181,7 +199,7 @@ public Task Delete(string contactId, CancellationToken cancellationToken = defau { _logger?.LogDebug("Deleting a {contactId} from {projectId}", contactId, _projectId); var uri = new Uri(_baseAddress, $"/v1/projects/{_projectId}/contacts/{contactId}"); - return _http.Send(uri, HttpMethod.Delete, cancellationToken: cancellationToken); + return _http.Send(uri, HttpMethod.Delete, cancellationToken); } /// @@ -191,7 +209,7 @@ public Task GetChannelProfile(GetChannelProfileRequest request, _logger?.LogDebug("Getting a profile for {projectId} of {channel}", _projectId, request.Channel); var uri = new Uri(_baseAddress, $"/v1/projects/{_projectId}/contacts:getChannelProfile"); return _http.Send(uri, HttpMethod.Post, request, - cancellationToken: cancellationToken); + cancellationToken); } /// @@ -200,7 +218,22 @@ public Task Update(Contact contact, CancellationToken cancellationToken _logger?.LogDebug("Updating a {contactId} of {projectId}", contact.Id, _projectId); var uri = new Uri(_baseAddress, $"/v1/projects/{_projectId}/contacts/{contact.Id}"); return _http.Send(uri, HttpMethod.Patch, contact, - cancellationToken: cancellationToken); + cancellationToken); + } + + /// + public Task Merge(string destinationId, string sourceId, CancellationToken cancellationToken = default) + { + _logger?.LogDebug("Merging contacts from {sourceId} to {destinationId} for {projectId}", sourceId, + destinationId, _projectId); + var uri = new Uri(_baseAddress, $"/v1/projects/{_projectId}/contacts/{destinationId}:merge"); + return _http.Send(uri, HttpMethod.Post, new + { + source_id = sourceId, + // NOTE: keep in mind while this enum has only one value, it can change in the future. + strategy = "MERGE" + }, + cancellationToken); } } } diff --git a/tests/Sinch.Tests/e2e/Conversation/ContactsTests.cs b/tests/Sinch.Tests/e2e/Conversation/ContactsTests.cs index 329a62c5..4f68b5f2 100644 --- a/tests/Sinch.Tests/e2e/Conversation/ContactsTests.cs +++ b/tests/Sinch.Tests/e2e/Conversation/ContactsTests.cs @@ -203,5 +203,13 @@ public async Task Update() var response = await SinchClientMockServer.Conversation.Contacts.Update(contact); response.Should().BeEquivalentTo(contact); } + + + [Fact] + public async Task Merge() + { + var response = await SinchClientMockServer.Conversation.Contacts.Merge("123ABC", "456EDF"); + response.Should().NotBeNull(); + } } }