Merge pull request #96 from onerain88/friend

好友和信息流
oneRain 2021-01-14 15:33:08 +08:00 committed by GitHub
commit 0d86389279
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 748 additions and 85 deletions

View File

@ -130,6 +130,24 @@
<Compile Include="..\Storage\Leaderboard\LCRanking.cs">
<Link>Leaderboard\LCRanking.cs</Link>
</Compile>
<Compile Include="..\Storage\LCFollowersAndFollowees.cs">
<Link>LCFollowersAndFollowees.cs</Link>
</Compile>
<Compile Include="..\Storage\LCFriendship.cs">
<Link>LCFriendship.cs</Link>
</Compile>
<Compile Include="..\Storage\LCFriendshipRequest.cs">
<Link>LCFriendshipRequest.cs</Link>
</Compile>
<Compile Include="..\Storage\LCStatus.cs">
<Link>LCStatus.cs</Link>
</Compile>
<Compile Include="..\Storage\LCStatusCount.cs">
<Link>LCStatusCount.cs</Link>
</Compile>
<Compile Include="..\Storage\LCStatusQuery.cs">
<Link>LCStatusQuery.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">

View File

@ -0,0 +1,103 @@
using NUnit.Framework;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using LeanCloud;
using LeanCloud.Storage;
namespace Storage.Test {
public class FriendTest {
async Task<LCUser> SignUp() {
LCUser user = new LCUser {
Username = Guid.NewGuid().ToString(),
Password = "world"
};
return await user.SignUp();
}
async Task<LCFriendshipRequest> GetRequest() {
LCUser user = await LCUser.GetCurrent();
LCQuery<LCFriendshipRequest> query = new LCQuery<LCFriendshipRequest>("_FriendshipRequest")
.WhereEqualTo("friend", user)
.WhereEqualTo("status", "pending");
return await query.First();
}
async Task<ReadOnlyCollection<LCObject>> GetFriends() {
LCUser user = await LCUser.GetCurrent();
LCQuery<LCObject> query = new LCQuery<LCObject>("_Followee")
.WhereEqualTo("user", user)
.WhereEqualTo("friendStatus", true);
return await query.Find();
}
private LCUser user1;
private LCUser user2;
[SetUp]
public void SetUp() {
LCLogger.LogDelegate += Utils.Print;
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo",
"https://ikggdre2.lc-cn-n1-shared.com");
}
[TearDown]
public void TearDown() {
LCLogger.LogDelegate -= Utils.Print;
}
[Test]
[Order(0)]
public async Task Init() {
user1 = await SignUp();
user2 = await SignUp();
Dictionary<string, object> attrs = new Dictionary<string, object> {
{ "group", "sport" }
};
await LCFriendship.Request(user1.ObjectId, attrs);
await SignUp();
await LCFriendship.Request(user1.ObjectId);
await LCUser.BecomeWithSessionToken(user1.SessionToken);
}
[Test]
[Order(1)]
public async Task Accept() {
// 查询好友请求
LCFriendshipRequest request = await GetRequest();
// 接受
await LCFriendship.AcceptRequest(request);
// 查询好友
Assert.Greater((await GetFriends()).Count, 0);
}
[Test]
[Order(2)]
public async Task Decline() {
// 查询好友请求
LCFriendshipRequest request = await GetRequest();
// 拒绝
await LCFriendship.DeclineRequest(request);
}
[Test]
[Order(3)]
public async Task Attributes() {
LCObject followee = (await GetFriends()).First();
followee["group"] = "friend";
await followee.Save();
}
[Test]
[Order(4)]
public async Task Delete() {
await user1.Unfollow(user2.ObjectId);
// 查询好友
Assert.AreEqual((await GetFriends()).Count, 0);
}
}
}

View File

@ -0,0 +1,143 @@
using NUnit.Framework;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using LeanCloud;
using LeanCloud.Storage;
namespace Storage.Test {
public class StatusTest {
private LCUser user1;
private LCUser user2;
private LCUser user3;
[SetUp]
public void SetUp() {
LCLogger.LogDelegate += Utils.Print;
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo",
"https://ikggdre2.lc-cn-n1-shared.com");
}
[TearDown]
public void TearDown() {
LCLogger.LogDelegate -= Utils.Print;
}
[Test]
[Order(0)]
public async Task Init() {
user1 = new LCUser {
Username = Guid.NewGuid().ToString(),
Password = "world"
};
await user1.SignUp();
user2 = new LCUser {
Username = Guid.NewGuid().ToString(),
Password = "world"
};
await user2.SignUp();
user3 = new LCUser {
Username = Guid.NewGuid().ToString(),
Password = "world"
};
await user3.SignUp();
}
[Test]
[Order(1)]
public async Task Follow() {
await LCUser.BecomeWithSessionToken(user2.SessionToken);
Dictionary<string, object> attrs = new Dictionary<string, object> {
{ "score", 100 }
};
await user2.Follow(user1.ObjectId, attrs);
await LCUser.BecomeWithSessionToken(user3.SessionToken);
await user3.Follow(user2.ObjectId);
}
[Test]
[Order(2)]
public async Task QueryFollowersAndFollowees() {
await LCUser.BecomeWithSessionToken(user2.SessionToken);
LCQuery<LCObject> query = user2.FolloweeQuery();
ReadOnlyCollection<LCObject> results = await query.Find();
Assert.Greater(results.Count, 0);
foreach (LCObject item in results) {
Assert.IsTrue(item["followee"] is LCObject);
Assert.AreEqual(user1.ObjectId, (item["followee"] as LCObject).ObjectId);
}
query = user2.FollowerQuery();
results = await query.Find();
Assert.Greater(results.Count, 0);
foreach (LCObject item in results) {
Assert.IsTrue(item["follower"] is LCObject);
Assert.AreEqual(user3.ObjectId, (item["follower"] as LCObject).ObjectId);
}
LCFollowersAndFollowees followersAndFollowees = await user2.GetFollowersAndFollowees(true, true, true);
Assert.AreEqual(followersAndFollowees.FollowersCount, 1);
Assert.AreEqual(followersAndFollowees.FolloweesCount, 1);
}
[Test]
[Order(3)]
public async Task Send() {
await LCUser.BecomeWithSessionToken(user1.SessionToken);
// 给粉丝发送状态
LCStatus status = new LCStatus {
Data = new Dictionary<string, object> {
{ "image", "xxx.jpg" },
{ "content", "hello, world" }
}
};
await LCStatus.SendToFollowers(status);
// 给某个用户发送私信
LCStatus privateStatus = new LCStatus {
Data = new Dictionary<string, object> {
{ "image", "xxx.jpg" },
{ "content", "hello, game" }
}
};
await LCStatus.SendPrivately(privateStatus, user2.ObjectId);
}
[Test]
[Order(4)]
public async Task Query() {
await Task.Delay(5000);
await LCUser.BecomeWithSessionToken(user2.SessionToken);
LCStatusCount statusCount = await LCStatus.GetCount(LCStatus.InboxTypeDefault);
Assert.Greater(statusCount.Total, 0);
LCStatusCount privateCount = await LCStatus.GetCount(LCStatus.InboxTypePrivate);
Assert.Greater(privateCount.Total, 0);
LCStatusQuery query = new LCStatusQuery(LCStatus.InboxTypeDefault);
ReadOnlyCollection<LCStatus> statuses = await query.Find();
foreach (LCStatus status in statuses) {
Assert.AreEqual((status["source"] as LCObject).ObjectId, user1.ObjectId);
await status.Delete();
}
await LCStatus.ResetUnreadCount(LCStatus.InboxTypePrivate);
}
[Test]
[Order(5)]
public async Task Unfollow() {
await LCUser.BecomeWithSessionToken(user2.SessionToken);
await user2.Unfollow(user1.ObjectId);
await LCUser.BecomeWithSessionToken(user3.SessionToken);
await user3.Unfollow(user1.ObjectId);
}
}
}

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using LeanCloud;
using LeanCloud.Storage;
using Newtonsoft.Json;
namespace Storage.Test {
public class UserTest {
@ -26,7 +27,8 @@ namespace Storage.Test {
user.Password = "world";
string email = $"{unixTime}@qq.com";
user.Email = email;
string mobile = $"{unixTime / 100}";
Random random = new Random();
string mobile = $"151{random.Next(10000000, 99999999)}";
user.Mobile = mobile;
await user.SignUp();
@ -72,7 +74,6 @@ namespace Storage.Test {
LCObject account = new LCObject("Account");
account["user"] = user;
await account.Save();
Assert.AreEqual(user.ObjectId, "5e0d5c667d5774006a5c1177");
}
[Test]
@ -239,7 +240,36 @@ namespace Storage.Test {
[Test]
public async Task VerifyCodeForUpdatingPhoneNumber() {
await LCUser.Login("hello", "world");
await LCUser.VerifyCodeForUpdatingPhoneNumber("15101006007", "055595");
await LCUser.VerifyCodeForUpdatingPhoneNumber("15101006007", "969327");
}
[Test]
public async Task AuthData() {
string uuid = Guid.NewGuid().ToString();
Dictionary<string, object> authData = new Dictionary<string, object> {
{ "expires_in", 7200 },
{ "openid", uuid },
{ "access_token", uuid }
};
LCUser currentUser = await LCUser.LoginWithAuthData(authData, "weixin");
TestContext.WriteLine(currentUser.SessionToken);
Assert.NotNull(currentUser.SessionToken);
string userId = currentUser.ObjectId;
TestContext.WriteLine($"userId: {userId}");
TestContext.WriteLine(JsonConvert.SerializeObject(currentUser.AuthData));
try {
authData = new Dictionary<string, object> {
{ "expires_in", 7200 },
{ "openid", uuid },
{ "access_token", uuid }
};
await currentUser.AssociateAuthData(authData, "qq");
TestContext.WriteLine(JsonConvert.SerializeObject(currentUser.AuthData));
} catch (LCException e) {
TestContext.WriteLine($"{e.Code} : {e.Message}");
TestContext.WriteLine(JsonConvert.SerializeObject(currentUser.AuthData));
}
}
}
}

View File

@ -42,40 +42,42 @@ namespace LeanCloud.Storage.Internal.Http {
md5 = MD5.Create();
}
public async Task<T> Get<T>(string path,
public Task<T> Get<T>(string path,
Dictionary<string, object> headers = null,
Dictionary<string, object> queryParams = null) {
string url = await BuildUrl(path, queryParams);
HttpRequestMessage request = new HttpRequestMessage {
RequestUri = new Uri(url),
Method = HttpMethod.Get
};
await FillHeaders(request.Headers, headers);
LCHttpUtils.PrintRequest(client, request);
HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
request.Dispose();
string resultString = await response.Content.ReadAsStringAsync();
response.Dispose();
LCHttpUtils.PrintResponse(response, resultString);
if (response.IsSuccessStatusCode) {
T ret = JsonConvert.DeserializeObject<T>(resultString,
LCJsonConverter.Default);
return ret;
}
throw HandleErrorResponse(response.StatusCode, resultString);
return Request<T>(path, HttpMethod.Get, headers, null, queryParams);
}
public async Task<T> Post<T>(string path,
public Task<T> Post<T>(string path,
Dictionary<string, object> headers = null,
object data = null,
Dictionary<string, object> queryParams = null) {
return Request<T>(path, HttpMethod.Post, headers, data, queryParams);
}
public Task<T> Put<T>(string path,
Dictionary<string, object> headers = null,
object data = null,
Dictionary<string, object> queryParams = null) {
return Request<T>(path, HttpMethod.Put, headers, data, queryParams);
}
public Task Delete(string path,
Dictionary<string, object> headers = null,
object data = null,
Dictionary<string, object> queryParams = null) {
return Request<Dictionary<string, object>>(path, HttpMethod.Delete, headers, data, queryParams);
}
async Task<T> Request<T>(string path,
HttpMethod method,
Dictionary<string, object> headers = null,
object data = null,
Dictionary<string, object> queryParams = null) {
string url = await BuildUrl(path, queryParams);
HttpRequestMessage request = new HttpRequestMessage {
RequestUri = new Uri(url),
Method = HttpMethod.Post,
Method = method,
};
await FillHeaders(request.Headers, headers);
@ -102,64 +104,6 @@ namespace LeanCloud.Storage.Internal.Http {
throw HandleErrorResponse(response.StatusCode, resultString);
}
public async Task<T> Put<T>(string path,
Dictionary<string, object> headers = null,
object data = null,
Dictionary<string, object> queryParams = null) {
string url = await BuildUrl(path, queryParams);
HttpRequestMessage request = new HttpRequestMessage {
RequestUri = new Uri(url),
Method = HttpMethod.Put,
};
await FillHeaders(request.Headers, headers);
string content = null;
if (data != null) {
content = JsonConvert.SerializeObject(data);
StringContent requestContent = new StringContent(content);
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
request.Content = requestContent;
}
LCHttpUtils.PrintRequest(client, request, content);
HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
request.Dispose();
string resultString = await response.Content.ReadAsStringAsync();
response.Dispose();
LCHttpUtils.PrintResponse(response, resultString);
if (response.IsSuccessStatusCode) {
T ret = JsonConvert.DeserializeObject<T>(resultString,
LCJsonConverter.Default);
return ret;
}
throw HandleErrorResponse(response.StatusCode, resultString);
}
public async Task Delete(string path) {
string url = await BuildUrl(path);
HttpRequestMessage request = new HttpRequestMessage {
RequestUri = new Uri(url),
Method = HttpMethod.Delete
};
await FillHeaders(request.Headers);
LCHttpUtils.PrintRequest(client, request);
HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
request.Dispose();
string resultString = await response.Content.ReadAsStringAsync();
response.Dispose();
LCHttpUtils.PrintResponse(response, resultString);
if (response.IsSuccessStatusCode) {
Dictionary<string, object> ret = JsonConvert.DeserializeObject<Dictionary<string, object>>(resultString,
LCJsonConverter.Default);
return;
}
throw HandleErrorResponse(response.StatusCode, resultString);
}
LCException HandleErrorResponse(HttpStatusCode statusCode, string responseContent) {
int code = (int)statusCode;
string message = responseContent;

View File

@ -61,6 +61,8 @@ namespace LeanCloud {
LCObject.RegisterSubclass(LCUser.CLASS_NAME, () => new LCUser());
LCObject.RegisterSubclass(LCRole.CLASS_NAME, () => new LCRole());
LCObject.RegisterSubclass(LCFile.CLASS_NAME, () => new LCFile());
LCObject.RegisterSubclass(LCStatus.CLASS_NAME, () => new LCStatus());
LCObject.RegisterSubclass(LCFriendshipRequest.CLASS_NAME, () => new LCFriendshipRequest());
AppRouter = new LCAppRouter(appId, server);

View File

@ -0,0 +1,21 @@
using System.Collections.Generic;
namespace LeanCloud.Storage {
public class LCFollowersAndFollowees {
public List<LCObject> Followers {
get; internal set;
}
public List<LCObject> Followees {
get; internal set;
}
public int FollowersCount {
get; internal set;
}
public int FolloweesCount {
get; internal set;
}
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using LeanCloud.Storage.Internal.Codec;
namespace LeanCloud.Storage {
public static class LCFriendship {
public static async Task Request(string userId, Dictionary<string, object> attributes = null) {
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
string path = "users/friendshipRequests";
LCObject friend = LCObject.CreateWithoutData("_User", userId);
Dictionary<string, object> data = new Dictionary<string, object> {
{ "user", LCEncoder.EncodeLCObject(user) },
{ "friend", LCEncoder.EncodeLCObject(friend) },
};
if (attributes != null) {
data["friendship"] = attributes;
}
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
}
public static async Task AcceptRequest(LCFriendshipRequest request, Dictionary<string, object> attributes = null) {
if (request == null) {
throw new ArgumentNullException(nameof(request));
}
string path = $"users/friendshipRequests/{request.ObjectId}/accept";
Dictionary<string, object> data = null;
if (attributes != null) {
data = new Dictionary<string, object> {
{ "friendship", attributes }
};
}
await LCApplication.HttpClient.Put<Dictionary<string, object>>(path, data: data);
}
public static async Task DeclineRequest(LCFriendshipRequest request) {
if (request == null) {
throw new ArgumentNullException(nameof(request));
}
string path = $"users/friendshipRequests/{request.ObjectId}/decline";
await LCApplication.HttpClient.Put<Dictionary<string, object>>(path);
}
}
}

View File

@ -0,0 +1,8 @@
namespace LeanCloud.Storage {
public class LCFriendshipRequest : LCObject {
public const string CLASS_NAME = "_FriendshipRequest";
public LCFriendshipRequest() : base(CLASS_NAME) {
}
}
}

176
Storage/Storage/LCStatus.cs Normal file
View File

@ -0,0 +1,176 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using LeanCloud.Storage.Internal.Codec;
using LeanCloud.Storage.Internal.Object;
using Newtonsoft.Json;
namespace LeanCloud.Storage {
public class LCStatus : LCObject {
public const string CLASS_NAME = "_Status";
/// Public, shown on followees' timeline.
public const string InboxTypeDefault = "default";
/// Private.
public const string InboxTypePrivate = "private";
/// Keys
public const string SourceKey = "source";
public const string InboxTypeKey = "inboxType";
public const string OwnerKey = "owner";
public const string MessageIdKey = "messageId";
public int MessageId {
get; internal set;
}
public string InboxType {
get; internal set;
}
private LCQuery query;
public Dictionary<string, object> Data {
get; set;
}
public LCStatus() : base(CLASS_NAME) {
InboxType = InboxTypeDefault;
Data = new Dictionary<string, object>();
}
public static async Task<LCStatus> SendToFollowers(LCStatus status) {
if (status == null) {
throw new ArgumentNullException(nameof(status));
}
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
status.Data[SourceKey] = user;
LCQuery<LCObject> query = new LCQuery<LCObject>("_Follower")
.WhereEqualTo("user", user)
.Select("follower");
status.query = query;
status.InboxType = InboxTypeDefault;
return await status.Send();
}
public static async Task<LCStatus> SendPrivately(LCStatus status, string targetId) {
if (status == null) {
throw new ArgumentNullException(nameof(status));
}
if (string.IsNullOrEmpty(targetId)) {
throw new ArgumentNullException(nameof(targetId));
}
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
status.Data[SourceKey] = user;
LCQuery<LCObject> query = new LCQuery<LCObject>("_User")
.WhereEqualTo("objectId", targetId);
status.query = query;
status.InboxType = InboxTypePrivate;
return await status.Send();
}
public async Task<LCStatus> Send() {
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
Dictionary<string, object> formData = new Dictionary<string, object> {
{ InboxTypeKey, InboxType }
};
if (Data != null) {
formData["data"] = LCEncoder.Encode(Data);
}
if (query != null) {
Dictionary<string, object> queryData = new Dictionary<string, object> {
{ "className", query.ClassName }
};
Dictionary<string, object> ps = query.BuildParams();
if (ps.TryGetValue("where", out object whereObj) &&
whereObj is string where) {
queryData["where"] = JsonConvert.DeserializeObject(where);
}
if (ps.TryGetValue("keys", out object keys)) {
queryData["keys"] = keys;
}
formData["query"] = queryData;
}
Dictionary<string, object> response = await LCApplication.HttpClient.Post<Dictionary<string, object>>("statuses",
data: formData);
LCObjectData objectData = LCObjectData.Decode(response);
Merge(objectData);
return this;
}
public new async Task Delete() {
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
LCUser source = (Data[SourceKey] ?? this[SourceKey]) as LCUser;
if (source != null && source.ObjectId == user.ObjectId) {
await LCApplication.HttpClient.Delete($"statuses/{ObjectId}");
} else {
Dictionary<string, object> data = new Dictionary<string, object> {
{ OwnerKey, JsonConvert.SerializeObject(LCEncoder.Encode(user)) },
{ InboxTypeKey, InboxType },
{ MessageIdKey, MessageId }
};
await LCApplication.HttpClient.Delete("subscribe/statuses/inbox", queryParams: data);
}
}
public static async Task<LCStatusCount> GetCount(string inboxType) {
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
Dictionary<string, object> queryParams = new Dictionary<string, object> {
{ OwnerKey, JsonConvert.SerializeObject(LCEncoder.Encode(user)) }
};
if (!string.IsNullOrEmpty(inboxType)) {
queryParams[InboxTypeKey] = inboxType;
}
Dictionary<string, object> response = await LCApplication.HttpClient.Get<Dictionary<string, object>>("subscribe/statuses/count",
queryParams: queryParams);
LCStatusCount statusCount = new LCStatusCount {
Total = (int)response["total"],
Unread = (int)response["unread"]
};
return statusCount;
}
public static async Task ResetUnreadCount(string inboxType = null) {
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
Dictionary<string, object> queryParams = new Dictionary<string, object> {
{ OwnerKey, JsonConvert.SerializeObject(LCEncoder.Encode(user)) }
};
if (!string.IsNullOrEmpty(inboxType)) {
queryParams[InboxTypeKey] = inboxType;
}
await LCApplication.HttpClient.Post<Dictionary<string, object>>("subscribe/statuses/resetUnreadCount",
queryParams:queryParams);
}
}
}

View File

@ -0,0 +1,11 @@
namespace LeanCloud.Storage {
public class LCStatusCount {
public int Total {
get; set;
}
public int Unread {
get; set;
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Newtonsoft.Json;
using LeanCloud.Storage.Internal.Codec;
using LeanCloud.Storage.Internal.Object;
namespace LeanCloud.Storage {
public class LCStatusQuery : LCQuery<LCStatus> {
public string InboxType {
get; set;
}
public int SinceId {
get; set;
}
public int MaxId {
get; set;
}
public LCStatusQuery(string inboxType = LCStatus.InboxTypeDefault) : base("_Status") {
InboxType = inboxType;
SinceId = 0;
MaxId = 0;
}
public new async Task<ReadOnlyCollection<LCStatus>> Find() {
LCUser user = await LCUser.GetCurrent();
if (user == null) {
throw new ArgumentNullException("current user");
}
Dictionary<string, object> queryParams = new Dictionary<string, object> {
{ LCStatus.OwnerKey, JsonConvert.SerializeObject(LCEncoder.Encode(user)) },
{ LCStatus.InboxTypeKey, InboxType },
{ "where", BuildWhere() },
{ "sinceId", SinceId },
{ "maxId", MaxId },
{ "limit", Condition.Limit }
};
Dictionary<string, object> response = await LCApplication.HttpClient.Get<Dictionary<string, object>>("subscribe/statuses",
queryParams: queryParams);
List<object> results = response["results"] as List<object>;
List<LCStatus> statuses = new List<LCStatus>();
foreach (object item in results) {
LCObjectData objectData = LCObjectData.Decode(item as IDictionary);
LCStatus status = new LCStatus();
status.Merge(objectData);
status.MessageId = (int)objectData.CustomPropertyDict[LCStatus.MessageIdKey];
status.Data = objectData.CustomPropertyDict;
status.InboxType = objectData.CustomPropertyDict[LCStatus.InboxTypeKey] as string;
statuses.Add(status);
}
return statuses.AsReadOnly();
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.Generic;
using LeanCloud.Storage.Internal.Object;
@ -612,5 +613,103 @@ namespace LeanCloud.Storage {
};
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
}
/// <summary>
/// Follows a user.
/// </summary>
/// <param name="targetId"></param>
/// <param name="attrs"></param>
/// <returns></returns>
public async Task Follow(string targetId, Dictionary<string, object> attrs = null) {
if (string.IsNullOrEmpty(targetId)) {
throw new ArgumentNullException(nameof(targetId));
}
string path = $"users/self/friendship/{targetId}";
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: attrs);
}
/// <summary>
/// Unfollows a user.
/// </summary>
/// <param name="targetId"></param>
/// <returns></returns>
public async Task Unfollow(string targetId) {
if (string.IsNullOrEmpty(targetId)) {
throw new ArgumentNullException(nameof(targetId));
}
string path = $"users/self/friendship/{targetId}";
await LCApplication.HttpClient.Delete(path);
}
/// <summary>
/// Constructs a follower query.
/// </summary>
/// <returns></returns>
public LCQuery<LCObject> FollowerQuery() {
return new LCQuery<LCObject>("_Follower")
.WhereEqualTo("user", this)
.Include("follower");
}
/// <summary>
/// Constructs a followee query.
/// </summary>
/// <returns></returns>
public LCQuery<LCObject> FolloweeQuery() {
return new LCQuery<LCObject>("_Followee")
.WhereEqualTo("user", this)
.Include("followee");
}
public async Task<LCFollowersAndFollowees> GetFollowersAndFollowees(bool includeFollower = false,
bool includeFollowee = false, bool returnCount = false) {
Dictionary<string, object> queryParams = new Dictionary<string, object>();
if (returnCount) {
queryParams["count"] = 1;
}
if (includeFollower || includeFollowee) {
List<string> includes = new List<string>();
if (includeFollower) {
includes.Add("follower");
}
if (includeFollowee) {
includes.Add("followee");
}
queryParams["include"] = string.Join(",", includes);
}
string path = $"users/{ObjectId}/followersAndFollowees";
Dictionary<string, object> response = await LCApplication.HttpClient.Get<Dictionary<string, object>>(path,
queryParams: queryParams);
LCFollowersAndFollowees result = new LCFollowersAndFollowees();
if (response.TryGetValue("followers", out object followersObj) &&
(followersObj is List<object> followers)) {
result.Followers = new List<LCObject>();
foreach (object followerObj in followers) {
LCObjectData objectData = LCObjectData.Decode(followerObj as IDictionary);
LCObject follower = new LCObject("_Follower");
follower.Merge(objectData);
result.Followers.Add(follower);
}
}
if (response.TryGetValue("followees", out object followeesObj) &&
(followeesObj is List<object> followees)) {
result.Followees = new List<LCObject>();
foreach (object followeeObj in followees) {
LCObjectData objectData = LCObjectData.Decode(followeeObj as IDictionary);
LCObject followee = new LCObject("_Followee");
followee.Merge(objectData);
result.Followees.Add(followee);
}
}
if (response.TryGetValue("followers_count", out object followersCountObj) &&
(followersCountObj is int followersCount)) {
result.FollowersCount = followersCount;
}
if (response.TryGetValue("followees_count", out object followeesCountObj) &&
(followeesCountObj is int followeesCount)) {
result.FolloweesCount = followeesCount;
}
return result;
}
}
}