Skip to content

Commit fc6c9a3

Browse files
authored
Feature/add invites support (#126)
* Implement invites + Add invites mechanics to the sample project * Add InviteMembersAsync overload + simplify sampel project implementation + add code samples + refactor unit tester to support secondary client
1 parent 19658d8 commit fc6c9a3

33 files changed

Lines changed: 3271 additions & 104 deletions

Assets/Plugins/StreamChat/Core/IStreamChatClient.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ public interface IStreamChatClient : IDisposable, IStreamChatClientEventsListene
4242
/// Channel was deleted
4343
/// </summary>
4444
event ChannelDeleteHandler ChannelDeleted;
45+
46+
/// <summary>
47+
/// Invite to a <see cref="IStreamChannel"/> was received
48+
/// </summary>
49+
event ChannelInviteHandler ChannelInviteReceived;
50+
51+
/// <summary>
52+
/// Invite to a <see cref="IStreamChannel"/> was accepted
53+
/// </summary>
54+
event ChannelInviteHandler ChannelInviteAccepted;
55+
56+
/// <summary>
57+
/// Invite to a <see cref="IStreamChannel"/> was rejected
58+
/// </summary>
59+
event ChannelInviteHandler ChannelInviteRejected;
4560

4661
/// <summary>
4762
/// Current connection state

Assets/Plugins/StreamChat/Core/State/StreamStatefulModelBase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ internal StreamStatefulModelBase(string uniqueId, ICacheRepository<TStatefulMode
3535
InternalUniqueId = uniqueId;
3636
Repository.Track(Self);
3737
}
38+
39+
protected Dictionary<string, object> GetInternalAdditionalPropertiesDictionary() => _additionalProperties;
3840

3941
protected abstract string InternalUniqueId { get; set; }
4042

@@ -49,6 +51,8 @@ protected void LoadAdditionalProperties(Dictionary<string, object> additionalPro
4951
{
5052
//StreamTodo: investigate if there's a case we don't want to clear here
5153
//Without clear channel full update or partial update unset won't work because we'll ignore that WS sent channel without custom data
54+
55+
//StreamTodo: 2, wrap into _customData.Sync(additionalProperties); instead of having a collection here
5256

5357
_additionalProperties.Clear();
5458
foreach (var keyValuePair in additionalProperties)

Assets/Plugins/StreamChat/Core/StatefulModels/IStreamChannel.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,5 +514,41 @@ Task TruncateAsync(DateTimeOffset? truncatedAt = default, string systemMessage =
514514
/// Stop being a member (<see cref="IStreamChannelMember"/>) of this channel. Only possible if local user has the `Leave Own Channel` permission
515515
/// </summary>
516516
Task LeaveAsMemberChannelAsync();
517+
518+
/// <summary>
519+
/// Invite new members to this channel.
520+
/// </summary>
521+
/// <remarks>https://getstream.io/chat/docs/unity/channel_invites/?language=unity/</remarks>
522+
Task InviteMembersAsync(IEnumerable<string> userIds);
523+
524+
/// <summary>
525+
/// Invite new members to this channel.
526+
/// </summary>
527+
/// <remarks>https://getstream.io/chat/docs/unity/channel_invites/?language=unity/</remarks>
528+
Task InviteMembersAsync(params string[] userIds);
529+
530+
/// <summary>
531+
/// Invite new members to this channel.
532+
/// </summary>
533+
/// <remarks>https://getstream.io/chat/docs/unity/channel_invites/?language=unity/</remarks>
534+
Task InviteMembersAsync(IEnumerable<IStreamUser> users);
535+
536+
/// <summary>
537+
/// Invite new members to this channel.
538+
/// </summary>
539+
/// <remarks>https://getstream.io/chat/docs/unity/channel_invites/?language=unity/</remarks>
540+
Task InviteMembersAsync(params IStreamUser[] users);
541+
542+
/// <summary>
543+
/// Accept an invite to this channel
544+
/// </summary>
545+
/// <remarks>https://getstream.io/chat/docs/unity/channel_invites/?language=unity/#accepting-an-invite</remarks>
546+
Task AcceptInviteAsync();
547+
548+
/// <summary>
549+
/// Reject an invite to this channel
550+
/// </summary>
551+
/// <remarks>https://getstream.io/chat/docs/unity/channel_invites/?language=unity/#rejecting-an-invite</remarks>
552+
Task RejectInviteAsync();
517553
}
518554
}

Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,15 @@ public async Task LoadOlderMessagesAsync()
222222
}
223223

224224
//StreamTodo: LoadNewerMessages? This would only make sense if we would start somewhere in the history. Maybe its possible with search? You jump in to past message and scroll to load newer
225-
public async Task UpdateOverwriteAsync() //StreamTodo: NOT IMPLEMENTED
225+
public Task UpdateOverwriteAsync() //StreamTodo: NOT IMPLEMENTED
226226
{
227-
var response = await LowLevelClient.InternalChannelApi.UpdateChannelAsync(Type, Id,
228-
new UpdateChannelRequestInternalDTO
229-
{
230-
});
227+
throw new NotImplementedException();
228+
// var response = await LowLevelClient.InternalChannelApi.UpdateChannelAsync(Type, Id,
229+
// new UpdateChannelRequestInternalDTO
230+
// {
231+
// });
231232

232-
Cache.TryCreateOrUpdate(response.Channel);
233+
//Cache.TryCreateOrUpdate(response.Channel);
233234
}
234235

235236
public async Task UpdatePartialAsync(IDictionary<string, object> setFields = null,
@@ -451,6 +452,69 @@ public async Task RemoveMembersAsync(IEnumerable<string> userIds)
451452

452453
public Task LeaveAsMemberChannelAsync() => RemoveMembersAsync(Client.LocalUserData.User);
453454

455+
public async Task InviteMembersAsync(IEnumerable<string> userIds)
456+
{
457+
StreamAsserts.AssertNotNull(userIds, nameof(userIds));
458+
459+
var invites = new List<ChannelMemberRequestInternalDTO>();
460+
foreach (var uid in userIds)
461+
{
462+
invites.Add(new ChannelMemberRequestInternalDTO
463+
{
464+
UserId = uid
465+
});
466+
}
467+
468+
var updateRequest = GetUpdateRequestWithCurrentData();
469+
updateRequest.Invites = invites;
470+
471+
var response = await LowLevelClient.InternalChannelApi.UpdateChannelAsync(Type, Id, updateRequest);
472+
473+
Cache.TryCreateOrUpdate(response.Channel);
474+
foreach (var member in response.Members)
475+
{
476+
Cache.TryCreateOrUpdate(member);
477+
}
478+
}
479+
480+
public Task InviteMembersAsync(params string[] userIds) => InviteMembersAsync(userIds as IEnumerable<string>);
481+
482+
public Task InviteMembersAsync(IEnumerable<IStreamUser> users)
483+
{
484+
StreamAsserts.AssertNotNull(users, nameof(users));
485+
return InviteMembersAsync(users.Select(_ => _.Id));
486+
}
487+
488+
public Task InviteMembersAsync(params IStreamUser[] users) => InviteMembersAsync(users as IEnumerable<IStreamUser>);
489+
490+
public async Task AcceptInviteAsync()
491+
{
492+
var updateRequest = GetUpdateRequestWithCurrentData();
493+
updateRequest.AcceptInvite = true;
494+
495+
var response = await LowLevelClient.InternalChannelApi.UpdateChannelAsync(Type, Id, updateRequest);
496+
497+
Cache.TryCreateOrUpdate(response.Channel);
498+
foreach (var member in response.Members)
499+
{
500+
Cache.TryCreateOrUpdate(member);
501+
}
502+
}
503+
504+
public async Task RejectInviteAsync()
505+
{
506+
var updateRequest = GetUpdateRequestWithCurrentData();
507+
updateRequest.RejectInvite = true;
508+
509+
var response = await LowLevelClient.InternalChannelApi.UpdateChannelAsync(Type, Id, updateRequest);
510+
511+
Cache.TryCreateOrUpdate(response.Channel);
512+
foreach (var member in response.Members)
513+
{
514+
Cache.TryCreateOrUpdate(member);
515+
}
516+
}
517+
454518
//StreamTodo: write test
455519
public async Task MuteChannelAsync(int? milliseconds = default)
456520
{
@@ -939,5 +1003,18 @@ private void SortMessagesByCreatedAt()
9391003
{
9401004
_messages.Sort((msg1, msg2) => msg1.CreatedAt.CompareTo(msg2.CreatedAt));
9411005
}
1006+
1007+
private UpdateChannelRequestInternalDTO GetUpdateRequestWithCurrentData() => new UpdateChannelRequestInternalDTO
1008+
{
1009+
Data = new ChannelRequestInternalDTO
1010+
{
1011+
AutoTranslationEnabled = AutoTranslationEnabled,
1012+
AutoTranslationLanguage = AutoTranslationLanguage,
1013+
Disabled = Disabled,
1014+
Frozen = Frozen,
1015+
AdditionalProperties = GetInternalAdditionalPropertiesDictionary(),
1016+
Name = Name
1017+
},
1018+
};
9421019
}
9431020
}

Assets/Plugins/StreamChat/Core/StreamChatClient.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ namespace StreamChat.Core
4646
/// </summary>
4747
public delegate void ChannelDeleteHandler(string channelCid, string channelId, ChannelType channelType);
4848

49-
//StreamTodo: Handle restoring state after lost connection + include Unity Network Monitor
49+
//StreamTodo: Handle restoring state after lost connection
50+
51+
public delegate void ChannelInviteHandler(IStreamChannel channel, IStreamUser invitee);
5052

5153
public sealed class StreamChatClient : IStreamChatClient
5254
{
@@ -60,6 +62,10 @@ public sealed class StreamChatClient : IStreamChatClient
6062

6163
public event ChannelDeleteHandler ChannelDeleted;
6264

65+
public event ChannelInviteHandler ChannelInviteReceived;
66+
public event ChannelInviteHandler ChannelInviteAccepted;
67+
public event ChannelInviteHandler ChannelInviteRejected;
68+
6369
public const int QueryUsersLimitMaxValue = 30;
6470
public const int QueryUsersOffsetMaxValue = 1000;
6571

@@ -844,19 +850,28 @@ private void OnRemovedFromChannelNotification(
844850
//StreamTodo: IMPLEMENT
845851
}
846852

847-
private void OnInvitedNotification(NotificationInvitedEventInternalDTO obj)
853+
private void OnInvitedNotification(NotificationInvitedEventInternalDTO eventDto)
848854
{
849-
//StreamTodo: IMPLEMENT
855+
var channel = _cache.TryCreateOrUpdate(eventDto.Channel);
856+
var user = _cache.TryCreateOrUpdate(eventDto.User);
857+
858+
ChannelInviteReceived?.Invoke(channel, user);
850859
}
851860

852-
private void OnInviteAcceptedNotification(NotificationInviteAcceptedEventInternalDTO obj)
861+
private void OnInviteAcceptedNotification(NotificationInviteAcceptedEventInternalDTO eventDto)
853862
{
854-
//StreamTodo: IMPLEMENT
863+
var channel = _cache.TryCreateOrUpdate(eventDto.Channel);
864+
var user = _cache.TryCreateOrUpdate(eventDto.User);
865+
866+
ChannelInviteAccepted?.Invoke(channel, user);
855867
}
856868

857-
private void OnInviteRejectedNotification(NotificationInviteRejectedEventInternalDTO obj)
869+
private void OnInviteRejectedNotification(NotificationInviteRejectedEventInternalDTO eventDto)
858870
{
859-
//StreamTodo: IMPLEMENT
871+
var channel = _cache.TryCreateOrUpdate(eventDto.Channel);
872+
var user = _cache.TryCreateOrUpdate(eventDto.User);
873+
874+
ChannelInviteRejected?.Invoke(channel, user);
860875
}
861876

862877
private void OnReactionReceived(ReactionNewEventInternalDTO eventDto)

Assets/Plugins/StreamChat/SampleProject/Config/AppConfig.asset

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ MonoBehaviour:
1515
_viewFactoryConfig:
1616
_messageOptionsPopupPrefab: {fileID: 5378343205483587087, guid: b6c7f64cd6c991f48b045099bdd324a7, type: 3}
1717
_createNewChannelPopupPrefab: {fileID: 8926528666989219657, guid: 8d705e1b929f52f469855a34297cc5a9, type: 3}
18+
_inviteChannelMembersPopup: {fileID: 555744599652294315, guid: b435ad66df150884f95195211ff0e2f9, type: 3}
19+
inviteReceivedPopup: {fileID: 612576315916417125, guid: a7f43c43ced3f304696341427caeea16, type: 3}
1820
_errorPopupPrefab: {fileID: 6615067076462953508, guid: 8751c971eb857264a92846caef344d49, type: 3}
1921
_emojiConfig: {fileID: 11400000, guid: 21c7de3d66787c8428964e6da1fdad93, type: 2}

0 commit comments

Comments
 (0)