Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions samples/DocsExamples/UserPermissions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using StreamChat.Clients;
using StreamChat.Models;

namespace DocsExamples;

/// <summary>
/// Code examples for <see href="https://getstream.io/chat/docs/python/user_permissions/"/>
/// </summary>
internal class UserPermissions
{
private readonly IUserClient _userClient;
private readonly IChannelClient _channelClient;
private readonly IPermissionClient _permissionClient;
private readonly IChannelTypeClient _channelTypeClient;
private readonly IAppClient _appClient;

public UserPermissions()
{
var factory = new StreamClientFactory("{{ api_key }}", "{{ api_secret }}");
_userClient = factory.GetUserClient();
_channelClient = factory.GetChannelClient();
_permissionClient = factory.GetPermissionClient();
_channelTypeClient = factory.GetChannelTypeClient();
_appClient = factory.GetAppClient();
}

internal async Task ChangeUserRole()
{
var upsertResponse = await _userClient.UpdatePartialAsync(new UserPartialRequest
{
Id = "user-id",
Set = new Dictionary<string, object>
{
{ "role", "special_agent" }
}
});
}

internal async Task VerifyChannelMemberRoleAssigned()
{
var addMembersResponse
= await _channelClient.AddMembersAsync("channel-type", "channel-id", new[] { "user-id" });
Console.WriteLine(addMembersResponse.Members[0].ChannelRole); // channel role is equal to "channel_member"
}

internal async Task AssignRoles()
{
// User must be a member of the channel before you can assign channel role
var resp = await _channelClient.AssignRolesAsync("channel-type", "channel-id", new AssignRoleRequest
{
AssignRoles = new List<RoleAssignment>
{
new RoleAssignment { UserId = "user-id", ChannelRole = Role.ChannelModerator }
}
});
}

internal async Task CreateRole()
{
await _permissionClient.CreateRoleAsync("special_agent");
}

internal async Task DeleteRole()
{
await _permissionClient.DeleteRoleAsync("special_agent");
}

internal async Task ListPermissions()
{
var response = await _permissionClient.ListPermissionsAsync();
}

internal async Task UpdateGrantedPermissions()
{
// observe current grants of the channel type
var channelType = await _channelTypeClient.GetChannelTypeAsync("messaging");
Console.WriteLine(channelType.Grants);

// update "channel_member" role grants in "messaging" scope
var update = new ChannelTypeWithStringCommandsRequest
{
Grants = new Dictionary<string, List<string>>
{
{
// This will replace all existing grants of "channel_member" role
"channel_member", new List<string>
{
"read-channel", // allow access to the channel
"create-message", // create messages in the channel
"update-message-owner", // update own user messages
"delete-message-owner", // delete own user messages
}
},
}
};
await _channelTypeClient.UpdateChannelTypeAsync("messaging", update);
}

internal async Task RemoveGrantedPermissionsByCategory()
{
var update = new ChannelTypeWithStringCommandsRequest
{
Grants = new Dictionary<string, List<string>>
{
{ "guest", new List<string>() }, // removes all grants of "guest" role
{ "anonymous", new List<string>() }, // removes all grants of "anonymous" role
}
};
await _channelTypeClient.UpdateChannelTypeAsync("messaging", update);
}

internal async Task ResetGrantsToDefaultSettings()
{
var update = new ChannelTypeWithStringCommandsRequest
{
Grants = new Dictionary<string, List<string>>()
};
await _channelTypeClient.UpdateChannelTypeAsync("messaging", update);
}

internal async Task UpdateAppScopedGrants()
{
var settings = new AppSettingsRequest
{
Grants = new Dictionary<string, List<string>>
{
{ "anonymous", new List<string>() },
{ "guest", new List<string>() },
{ "user", new List<string> { "search-user", "mute-user" } },
{ "admin", new List<string> { "search-user", "mute-user", "ban-user" } },
}
};
await _appClient.UpdateAppSettingsAsync(settings);
}

internal async Task UpdateChannelLevelPermissions()
{
var grants = new Dictionary<string, object> { { "user", new List<string> { "!add-links", "create-reaction" } } };
var overrides = new Dictionary<string, object> { { "grants", grants } };
var request = new PartialUpdateChannelRequest
{
Set = new Dictionary<string, object>
{
{ "config_overrides", overrides }
}
};
var resp = await _channelClient.PartialUpdateAsync("channel-type", "channel-id", request);
}
}
6 changes: 3 additions & 3 deletions src/Clients/ChannelClient.Members.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ namespace StreamChat.Clients
{
public partial class ChannelClient
{
public async Task<ApiResponse> AddMembersAsync(string channelType, string channelId, params string[] userIds)
public async Task<UpdateChannelResponse> AddMembersAsync(string channelType, string channelId, params string[] userIds)
=> await AddMembersAsync(channelType, channelId, userIds, null, null);

public async Task<ApiResponse> AddMembersAsync(string channelType, string channelId, IEnumerable<string> userIds, MessageRequest msg, AddMemberOptions options)
=> await ExecuteRequestAsync<ApiResponse>($"channels/{channelType}/{channelId}",
public async Task<UpdateChannelResponse> AddMembersAsync(string channelType, string channelId, IEnumerable<string> userIds, MessageRequest msg, AddMemberOptions options)
=> await ExecuteRequestAsync<UpdateChannelResponse>($"channels/{channelType}/{channelId}",
HttpMethod.POST,
HttpStatusCode.Created,
new ChannelUpdateRequest
Expand Down
4 changes: 2 additions & 2 deletions src/Clients/IChannelClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ public interface IChannelClient
/// Adds members to a channel.
/// </summary>
/// <remarks>https://getstream.io/chat/docs/dotnet-csharp/channel_members/?language=csharp</remarks>
Task<ApiResponse> AddMembersAsync(string channelType, string channelId, params string[] userIds);
Task<UpdateChannelResponse> AddMembersAsync(string channelType, string channelId, params string[] userIds);

/// <summary>
/// Adds members to a channel.
/// </summary>
/// <remarks>https://getstream.io/chat/docs/dotnet-csharp/channel_members/?language=csharp</remarks>
Task<ApiResponse> AddMembersAsync(string channelType, string channelId, IEnumerable<string> userIds,
Task<UpdateChannelResponse> AddMembersAsync(string channelType, string channelId, IEnumerable<string> userIds,
MessageRequest msg, AddMemberOptions options);

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Models/Channel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class UpdateChannelResponse : ApiResponse
{
public ChannelWithConfig Channel { get; set; }
public Message Message { get; set; }
public List<ChannelMember> Members { get; set; }
}

public class PartialUpdateChannelRequest
Expand Down
1 change: 1 addition & 0 deletions src/Models/ChannelConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public abstract class ChannelConfigBase
public string MessageRetention { get; set; }
public int MaxMessageLength { get; set; }
public string Automod { get; set; }
public Dictionary<string, List<string>> Grants { get; set; }
}

public class ChannelConfig : ChannelConfigBase
Expand Down
1 change: 1 addition & 0 deletions src/Models/ChannelMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ChannelMember : CustomDataBase
public DateTimeOffset? InviteAcceptedAt { get; set; }
public DateTimeOffset? InviteRejectedAt { get; set; }
public string Role { get; set; }
public string ChannelRole { get; set; }
public DateTimeOffset? CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool? Banned { get; set; }
Expand Down
7 changes: 6 additions & 1 deletion src/Models/ChannelType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ public abstract class ChannelTypeRequestBase
[Obsolete("Use V2 Permissions APIs instead. " +
"See https://getstream.io/chat/docs/dotnet-csharp/migrating_from_legacy/?language=csharp")]
public List<ChannelTypePermission> Permissions { get; set; }
public Dictionary<string, List<string>> Grants { get; set; }

// JsonProperty is needed because passing NULL is a special case where API resets the grants to the default settings.
// Empty Dictionary as a default value is needed in order for the default object to not reset the grants
[JsonProperty(NullValueHandling = NullValueHandling.Include,
DefaultValueHandling = DefaultValueHandling.Include)]
public Dictionary<string, List<string>> Grants { get; set; } = new Dictionary<string, List<string>>();
}

public class ChannelTypeWithCommandsRequest : ChannelTypeRequestBase
Expand Down
8 changes: 4 additions & 4 deletions tests/BlocklistClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task TearDownAsync()
}

[Test]
public Task TestGetAsync() => TryMultiple(async () =>
public Task TestGetAsync() => TryMultipleAsync(async () =>
{
var resp = await _blocklistClient.GetAsync(_blocklistName);

Expand All @@ -47,7 +47,7 @@ public Task TestGetAsync() => TryMultiple(async () =>
});

[Test]
public Task TestListAsync() => TryMultiple(async () =>
public Task TestListAsync() => TryMultipleAsync(async () =>
{
var resp = await _blocklistClient.ListAsync();

Expand All @@ -59,12 +59,12 @@ public async Task TestUpdateAsync()
{
var expectedWords = new[] { "test", "test2" };

await TryMultiple(async () =>
await TryMultipleAsync(async () =>
{
await _blocklistClient.UpdateAsync(_blocklistName, expectedWords);
});

await TryMultiple(async () =>
await TryMultipleAsync(async () =>
{
var updated = await _blocklistClient.GetAsync(_blocklistName);
updated.Blocklist.Words.Should().BeEquivalentTo(expectedWords);
Expand Down
2 changes: 1 addition & 1 deletion tests/ChannelTypeClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ await WaitForAsync(async () =>

[Test]
public Task TestGetChannelTypeAsync()
=> TryMultiple(testBody: async () =>
=> TryMultipleAsync(testBody: async () =>
{
var actualChannelType = await _channelTypeClient.GetChannelTypeAsync(_channelType.Name);
actualChannelType.Name.Should().BeEquivalentTo(_channelType.Name);
Expand Down
4 changes: 2 additions & 2 deletions tests/CommandClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task TeardownAsync()

[Test]
public Task TestGetCommandAsync()
=> TryMultiple(async () =>
=> TryMultipleAsync(async () =>
{
var command = await _commandClient.GetAsync(_command.Name);

Expand All @@ -47,7 +47,7 @@ public Task TestGetCommandAsync()

[Test]
public Task TestListCommandsAsync()
=> TryMultiple(async () =>
=> TryMultipleAsync(async () =>
{
var resp = await _commandClient.ListAsync();

Expand Down
1 change: 0 additions & 1 deletion tests/ImportClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using NUnit.Framework;
Expand Down
Loading
Loading