Merge pull request #96 from onerain88/friend
好友和信息流
commit
0d86389279
|
@ -130,6 +130,24 @@
|
||||||
<Compile Include="..\Storage\Leaderboard\LCRanking.cs">
|
<Compile Include="..\Storage\Leaderboard\LCRanking.cs">
|
||||||
<Link>Leaderboard\LCRanking.cs</Link>
|
<Link>Leaderboard\LCRanking.cs</Link>
|
||||||
</Compile>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Newtonsoft.Json">
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LeanCloud;
|
using LeanCloud;
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Storage.Test {
|
namespace Storage.Test {
|
||||||
public class UserTest {
|
public class UserTest {
|
||||||
|
@ -26,7 +27,8 @@ namespace Storage.Test {
|
||||||
user.Password = "world";
|
user.Password = "world";
|
||||||
string email = $"{unixTime}@qq.com";
|
string email = $"{unixTime}@qq.com";
|
||||||
user.Email = email;
|
user.Email = email;
|
||||||
string mobile = $"{unixTime / 100}";
|
Random random = new Random();
|
||||||
|
string mobile = $"151{random.Next(10000000, 99999999)}";
|
||||||
user.Mobile = mobile;
|
user.Mobile = mobile;
|
||||||
await user.SignUp();
|
await user.SignUp();
|
||||||
|
|
||||||
|
@ -72,7 +74,6 @@ namespace Storage.Test {
|
||||||
LCObject account = new LCObject("Account");
|
LCObject account = new LCObject("Account");
|
||||||
account["user"] = user;
|
account["user"] = user;
|
||||||
await account.Save();
|
await account.Save();
|
||||||
Assert.AreEqual(user.ObjectId, "5e0d5c667d5774006a5c1177");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -239,7 +240,36 @@ namespace Storage.Test {
|
||||||
[Test]
|
[Test]
|
||||||
public async Task VerifyCodeForUpdatingPhoneNumber() {
|
public async Task VerifyCodeForUpdatingPhoneNumber() {
|
||||||
await LCUser.Login("hello", "world");
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,40 +42,42 @@ namespace LeanCloud.Storage.Internal.Http {
|
||||||
md5 = MD5.Create();
|
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> headers = null,
|
||||||
Dictionary<string, object> queryParams = null) {
|
Dictionary<string, object> queryParams = null) {
|
||||||
string url = await BuildUrl(path, queryParams);
|
return Request<T>(path, HttpMethod.Get, headers, null, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
Dictionary<string, object> headers = null,
|
||||||
object data = null,
|
object data = null,
|
||||||
Dictionary<string, object> queryParams = null) {
|
Dictionary<string, object> queryParams = null) {
|
||||||
string url = await BuildUrl(path, queryParams);
|
string url = await BuildUrl(path, queryParams);
|
||||||
HttpRequestMessage request = new HttpRequestMessage {
|
HttpRequestMessage request = new HttpRequestMessage {
|
||||||
RequestUri = new Uri(url),
|
RequestUri = new Uri(url),
|
||||||
Method = HttpMethod.Post,
|
Method = method,
|
||||||
};
|
};
|
||||||
await FillHeaders(request.Headers, headers);
|
await FillHeaders(request.Headers, headers);
|
||||||
|
|
||||||
|
@ -102,64 +104,6 @@ namespace LeanCloud.Storage.Internal.Http {
|
||||||
throw HandleErrorResponse(response.StatusCode, resultString);
|
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) {
|
LCException HandleErrorResponse(HttpStatusCode statusCode, string responseContent) {
|
||||||
int code = (int)statusCode;
|
int code = (int)statusCode;
|
||||||
string message = responseContent;
|
string message = responseContent;
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace LeanCloud {
|
||||||
LCObject.RegisterSubclass(LCUser.CLASS_NAME, () => new LCUser());
|
LCObject.RegisterSubclass(LCUser.CLASS_NAME, () => new LCUser());
|
||||||
LCObject.RegisterSubclass(LCRole.CLASS_NAME, () => new LCRole());
|
LCObject.RegisterSubclass(LCRole.CLASS_NAME, () => new LCRole());
|
||||||
LCObject.RegisterSubclass(LCFile.CLASS_NAME, () => new LCFile());
|
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);
|
AppRouter = new LCAppRouter(appId, server);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace LeanCloud.Storage {
|
||||||
|
public class LCFriendshipRequest : LCObject {
|
||||||
|
public const string CLASS_NAME = "_FriendshipRequest";
|
||||||
|
|
||||||
|
public LCFriendshipRequest() : base(CLASS_NAME) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace LeanCloud.Storage {
|
||||||
|
public class LCStatusCount {
|
||||||
|
public int Total {
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Unread {
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using LeanCloud.Storage.Internal.Object;
|
using LeanCloud.Storage.Internal.Object;
|
||||||
|
|
||||||
|
@ -612,5 +613,103 @@ namespace LeanCloud.Storage {
|
||||||
};
|
};
|
||||||
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue