chore: 简化 AVUser

oneRain 2019-08-21 17:55:08 +08:00
parent c303a5d307
commit e68a13590a
3 changed files with 135 additions and 386 deletions

View File

@ -5,14 +5,14 @@ using System.Net.Http;
namespace LeanCloud.Storage.Internal { namespace LeanCloud.Storage.Internal {
public class AVUserController { public class AVUserController {
public async Task<IObjectState> SignUpAsync(IObjectState state, IDictionary<string, IAVFieldOperation> operations, CancellationToken cancellationToken) { public async Task<IObjectState> SignUpAsync(IObjectState state, IDictionary<string, IAVFieldOperation> operations) {
var objectJSON = AVObject.ToJSONObjectForSaving(operations); var objectJSON = AVObject.ToJSONObjectForSaving(operations);
var command = new AVCommand { var command = new AVCommand {
Path = "classes/_User", Path = "classes/_User",
Method = HttpMethod.Post, Method = HttpMethod.Post,
Content = objectJSON Content = objectJSON
}; };
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken); var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance); var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => { serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = true; mutableClone.IsNew = true;
@ -43,7 +43,7 @@ namespace LeanCloud.Storage.Internal {
return serverState; return serverState;
} }
public async Task<IObjectState> LogInAsync(string authType, IDictionary<string, object> data, bool failOnNotExist, CancellationToken cancellationToken) { public async Task<IObjectState> LogInAsync(string authType, IDictionary<string, object> data, bool failOnNotExist) {
var authData = new Dictionary<string, object> { var authData = new Dictionary<string, object> {
[authType] = data [authType] = data
}; };
@ -55,7 +55,7 @@ namespace LeanCloud.Storage.Internal {
{ "authData", authData} { "authData", authData}
} }
}; };
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken); var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance); var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => { serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created; mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created;

View File

@ -6,8 +6,7 @@ using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace LeanCloud namespace LeanCloud {
{
/// <summary> /// <summary>
/// AVFile is a local representation of a file that is saved to the LeanCloud. /// AVFile is a local representation of a file that is saved to the LeanCloud.
/// </summary> /// </summary>
@ -24,8 +23,7 @@ namespace LeanCloud
/// await obj.SaveAsync(); /// await obj.SaveAsync();
/// </code> /// </code>
/// </example> /// </example>
public partial class AVFile : IJsonConvertible public partial class AVFile : IJsonConvertible {
{
internal static int objectCounter = 0; internal static int objectCounter = 0;
internal static readonly object Mutex = new object(); internal static readonly object Mutex = new object();
private FileState state; private FileState state;
@ -40,18 +38,15 @@ namespace LeanCloud
/// <param name="data">数据流</param> /// <param name="data">数据流</param>
/// <param name="mimeType">文件类型</param> /// <param name="mimeType">文件类型</param>
/// <param name="metaData">文件源信息</param> /// <param name="metaData">文件源信息</param>
public AVFile(string name, Stream data, string mimeType = null, IDictionary<string, object> metaData = null) public AVFile(string name, Stream data, string mimeType = null, IDictionary<string, object> metaData = null) {
{
mimeType = mimeType == null ? GetMIMEType(name) : mimeType; mimeType = mimeType == null ? GetMIMEType(name) : mimeType;
state = new FileState state = new FileState {
{
Name = name, Name = name,
MimeType = mimeType, MimeType = mimeType,
MetaData = metaData MetaData = metaData
}; };
this.dataStream = data; this.dataStream = data;
lock (Mutex) lock (Mutex) {
{
objectCounter++; objectCounter++;
state.counter = objectCounter; state.counter = objectCounter;
} }
@ -73,8 +68,7 @@ namespace LeanCloud
/// <param name="data">文件流数据</param> /// <param name="data">文件流数据</param>
/// <param name="mimeType">文件类型</param> /// <param name="mimeType">文件类型</param>
public AVFile(string name, Stream data, string mimeType = null) public AVFile(string name, Stream data, string mimeType = null)
: this(name, data, mimeType, new Dictionary<string, object>()) : this(name, data, mimeType, new Dictionary<string, object>()) {
{
} }
/// <summary> /// <summary>
@ -83,8 +77,7 @@ namespace LeanCloud
/// <param name="name">文件名</param> /// <param name="name">文件名</param>
/// <param name="data">文件的 byte[] 数据</param> /// <param name="data">文件的 byte[] 数据</param>
public AVFile(string name, byte[] data) public AVFile(string name, byte[] data)
: this(name, new MemoryStream(data), new Dictionary<string, object>()) : this(name, new MemoryStream(data), new Dictionary<string, object>()) {
{
} }
@ -95,8 +88,7 @@ namespace LeanCloud
/// <param name="data">文件的 byte[] 数据</param> /// <param name="data">文件的 byte[] 数据</param>
/// <param name="metaData">元数据</param> /// <param name="metaData">元数据</param>
public AVFile(string name, byte[] data, IDictionary<string, object> metaData) public AVFile(string name, byte[] data, IDictionary<string, object> metaData)
: this(name, new MemoryStream(data), metaData) : this(name, new MemoryStream(data), metaData) {
{
} }
@ -107,8 +99,7 @@ namespace LeanCloud
/// <param name="data">文件的数据流</param> /// <param name="data">文件的数据流</param>
/// <param name="metaData">元数据</param> /// <param name="metaData">元数据</param>
public AVFile(string name, Stream data, IDictionary<string, object> metaData) public AVFile(string name, Stream data, IDictionary<string, object> metaData)
: this(name, data, GetMIMEType(name), metaData) : this(name, data, GetMIMEType(name), metaData) {
{
} }
/// <summary> /// <summary>
@ -117,8 +108,7 @@ namespace LeanCloud
/// <param name="name">文件名</param> /// <param name="name">文件名</param>
/// <param name="data">文件的数据流</param> /// <param name="data">文件的数据流</param>
public AVFile(string name, Stream data) public AVFile(string name, Stream data)
: this(name, data, new Dictionary<string, object>()) : this(name, data, new Dictionary<string, object>()) {
{
} }
@ -130,18 +120,15 @@ namespace LeanCloud
/// <param name="uri">文件Uri</param> /// <param name="uri">文件Uri</param>
/// <param name="mimeType">文件类型</param> /// <param name="mimeType">文件类型</param>
/// <param name="metaData">文件源信息</param> /// <param name="metaData">文件源信息</param>
public AVFile(string name, Uri uri, string mimeType = null, IDictionary<string, object> metaData = null) public AVFile(string name, Uri uri, string mimeType = null, IDictionary<string, object> metaData = null) {
{
mimeType = mimeType == null ? GetMIMEType(name) : mimeType; mimeType = mimeType == null ? GetMIMEType(name) : mimeType;
state = new FileState state = new FileState {
{
Name = name, Name = name,
Url = uri, Url = uri,
MetaData = metaData, MetaData = metaData,
MimeType = mimeType MimeType = mimeType
}; };
lock (Mutex) lock (Mutex) {
{
objectCounter++; objectCounter++;
state.counter = objectCounter; state.counter = objectCounter;
} }
@ -156,8 +143,7 @@ namespace LeanCloud
/// <param name="mimeType">文件类型</param> /// <param name="mimeType">文件类型</param>
/// <param name="metaData">文件源信息</param> /// <param name="metaData">文件源信息</param>
public AVFile(string name, string url, string mimeType = null, IDictionary<string, object> metaData = null) public AVFile(string name, string url, string mimeType = null, IDictionary<string, object> metaData = null)
: this(name, new Uri(url), mimeType, metaData) : this(name, new Uri(url), mimeType, metaData) {
{
} }
@ -168,8 +154,7 @@ namespace LeanCloud
/// <param name="url">文件 Url</param> /// <param name="url">文件 Url</param>
/// <param name="metaData">文件源信息</param> /// <param name="metaData">文件源信息</param>
public AVFile(string name, string url, IDictionary<string, object> metaData) public AVFile(string name, string url, IDictionary<string, object> metaData)
: this(name, url, null, metaData) : this(name, url, null, metaData) {
{
} }
/// <summary> /// <summary>
@ -179,8 +164,7 @@ namespace LeanCloud
/// <param name="uri">文件 Uri</param> /// <param name="uri">文件 Uri</param>
/// <param name="mimeType">文件类型</param> /// <param name="mimeType">文件类型</param>
public AVFile(string name, Uri uri, string mimeType = null) public AVFile(string name, Uri uri, string mimeType = null)
: this(name, uri, mimeType, new Dictionary<string, object>()) : this(name, uri, mimeType, new Dictionary<string, object>()) {
{
} }
@ -190,8 +174,7 @@ namespace LeanCloud
/// <param name="name">文件名</param> /// <param name="name">文件名</param>
/// <param name="uri">文件 Uri</param> /// <param name="uri">文件 Uri</param>
public AVFile(string name, Uri uri) public AVFile(string name, Uri uri)
: this(name, uri, null, new Dictionary<string, object>()) : this(name, uri, null, new Dictionary<string, object>()) {
{
} }
/// <summary> /// <summary>
@ -200,20 +183,16 @@ namespace LeanCloud
/// <param name="name">文件名</param> /// <param name="name">文件名</param>
/// <param name="url">文件的 Url</param> /// <param name="url">文件的 Url</param>
public AVFile(string name, string url) public AVFile(string name, string url)
: this(name, new Uri(url)) : this(name, new Uri(url)) {
{
} }
internal AVFile(FileState filestate) internal AVFile(FileState filestate) {
{
this.state = filestate; this.state = filestate;
} }
internal AVFile(string objectId) internal AVFile(string objectId)
: this(new FileState() : this(new FileState() {
{
ObjectId = objectId ObjectId = objectId
}) }) {
{
} }
#endregion #endregion
@ -225,10 +204,8 @@ namespace LeanCloud
/// <summary> /// <summary>
/// Gets whether the file still needs to be saved. /// Gets whether the file still needs to be saved.
/// </summary> /// </summary>
public bool IsDirty public bool IsDirty {
{ get {
get
{
return state.Url == null; return state.Url == null;
} }
} }
@ -238,10 +215,8 @@ namespace LeanCloud
/// the user. After save is called, that name gets prefixed with a unique identifier. /// the user. After save is called, that name gets prefixed with a unique identifier.
/// </summary> /// </summary>
[AVFieldName("name")] [AVFieldName("name")]
public string Name public string Name {
{ get {
get
{
return state.Name; return state.Name;
} }
} }
@ -251,10 +226,8 @@ namespace LeanCloud
/// inferred from the file extension. "unknown/unknown" will be used if neither is /// inferred from the file extension. "unknown/unknown" will be used if neither is
/// available. /// available.
/// </summary> /// </summary>
public string MimeType public string MimeType {
{ get {
get
{
return state.MimeType; return state.MimeType;
} }
} }
@ -264,28 +237,22 @@ namespace LeanCloud
/// you get the file from a <see cref="AVObject"/>. /// you get the file from a <see cref="AVObject"/>.
/// </summary> /// </summary>
[AVFieldName("url")] [AVFieldName("url")]
public Uri Url public Uri Url {
{ get {
get
{
return state.Url; return state.Url;
} }
} }
internal static AVFileController FileController internal static AVFileController FileController {
{ get {
get
{
return AVPlugins.Instance.FileController; return AVPlugins.Instance.FileController;
} }
} }
#endregion #endregion
IDictionary<string, object> IJsonConvertible.ToJSON() IDictionary<string, object> IJsonConvertible.ToJSON() {
{ if (this.IsDirty) {
if (this.IsDirty)
{
throw new InvalidOperationException( throw new InvalidOperationException(
"AVFile must be saved before it can be serialized."); "AVFile must be saved before it can be serialized.");
} }
@ -302,8 +269,7 @@ namespace LeanCloud
/// <summary> /// <summary>
/// Saves the file to the LeanCloud cloud. /// Saves the file to the LeanCloud cloud.
/// </summary> /// </summary>
public Task SaveAsync() public Task SaveAsync() {
{
return SaveAsync(null, CancellationToken.None); return SaveAsync(null, CancellationToken.None);
} }
@ -311,8 +277,7 @@ namespace LeanCloud
/// Saves the file to the LeanCloud cloud. /// Saves the file to the LeanCloud cloud.
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
public Task SaveAsync(CancellationToken cancellationToken) public Task SaveAsync(CancellationToken cancellationToken) {
{
return SaveAsync(null, cancellationToken); return SaveAsync(null, cancellationToken);
} }
@ -320,8 +285,7 @@ namespace LeanCloud
/// Saves the file to the LeanCloud cloud. /// Saves the file to the LeanCloud cloud.
/// </summary> /// </summary>
/// <param name="progress">The progress callback.</param> /// <param name="progress">The progress callback.</param>
public Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress) public Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress) {
{
return SaveAsync(progress, CancellationToken.None); return SaveAsync(progress, CancellationToken.None);
} }
@ -331,21 +295,18 @@ namespace LeanCloud
/// <param name="progress">The progress callback.</param> /// <param name="progress">The progress callback.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
public Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress, public Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress,
CancellationToken cancellationToken) CancellationToken cancellationToken) {
{
if (this.isExternal) if (this.isExternal)
return this.SaveExternal(); return this.SaveExternal();
return taskQueue.Enqueue( return taskQueue.Enqueue(
toAwait => FileController.SaveAsync(state, dataStream, AVUser.CurrentUser.SessionToken, progress, cancellationToken), cancellationToken) toAwait => FileController.SaveAsync(state, dataStream, AVUser.CurrentUser.SessionToken, progress, cancellationToken), cancellationToken)
.OnSuccess(t => .OnSuccess(t => {
{
state = t.Result; state = t.Result;
}); });
} }
internal Task SaveExternal() internal Task SaveExternal() {
{
Dictionary<string, object> strs = new Dictionary<string, object>() Dictionary<string, object> strs = new Dictionary<string, object>()
{ {
{ "url", this.Url.ToString() }, { "url", this.Url.ToString() },
@ -369,8 +330,7 @@ namespace LeanCloud
}; };
} }
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(cmd).OnSuccess(t => return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(cmd).OnSuccess(t => {
{
var result = t.Result.Item2; var result = t.Result.Item2;
state.ObjectId = result["objectId"].ToString(); state.ObjectId = result["objectId"].ToString();
}); });
@ -385,13 +345,10 @@ namespace LeanCloud
/// <summary> /// <summary>
/// 文件在 LeanCloud 的唯一Id 标识 /// 文件在 LeanCloud 的唯一Id 标识
/// </summary> /// </summary>
public string ObjectId public string ObjectId {
{ get {
get
{
String str; String str;
lock (this.mutex) lock (this.mutex) {
{
str = state.ObjectId; str = state.ObjectId;
} }
return str; return str;
@ -401,10 +358,8 @@ namespace LeanCloud
/// <summary> /// <summary>
/// 文件的元数据。 /// 文件的元数据。
/// </summary> /// </summary>
public IDictionary<string, object> MetaData public IDictionary<string, object> MetaData {
{ get {
get
{
return state.MetaData; return state.MetaData;
} }
} }
@ -414,16 +369,13 @@ namespace LeanCloud
/// </summary> /// </summary>
/// <value> /// <value>
/// </value> /// </value>
public bool IsExternal public bool IsExternal {
{ get {
get
{
return isExternal; return isExternal;
} }
} }
static AVFile() static AVFile() {
{
Dictionary<string, string> strs = new Dictionary<string, string>() Dictionary<string, string> strs = new Dictionary<string, string>()
{ {
{ "ai", "application/postscript" }, { "ai", "application/postscript" },
@ -617,19 +569,14 @@ namespace LeanCloud
}; };
AVFile.MIMETypesDictionary = strs; AVFile.MIMETypesDictionary = strs;
} }
internal static string GetMIMEType(string fileName) internal static string GetMIMEType(string fileName) {
{ try {
try
{
string str = Path.GetExtension(fileName).Remove(0, 1); string str = Path.GetExtension(fileName).Remove(0, 1);
if (!AVFile.MIMETypesDictionary.ContainsKey(str)) if (!AVFile.MIMETypesDictionary.ContainsKey(str)) {
{
return "unknown/unknown"; return "unknown/unknown";
} }
return AVFile.MIMETypesDictionary[str]; return AVFile.MIMETypesDictionary[str];
} } catch {
catch
{
return "unknown/unknown"; return "unknown/unknown";
} }
} }
@ -639,28 +586,23 @@ namespace LeanCloud
/// </summary> /// </summary>
/// <remarks>获取之后并没有实际执行下载只是加载了文件的元信息以及物理地址Url /// <remarks>获取之后并没有实际执行下载只是加载了文件的元信息以及物理地址Url
/// </remarks> /// </remarks>
public static Task<AVFile> GetFileWithObjectIdAsync(string objectId, CancellationToken cancellationToken) public static Task<AVFile> GetFileWithObjectIdAsync(string objectId, CancellationToken cancellationToken) {
{
string currentSessionToken = AVUser.CurrentUser.SessionToken; string currentSessionToken = AVUser.CurrentUser.SessionToken;
return FileController.GetAsync(objectId, currentSessionToken, cancellationToken).OnSuccess(_ => return FileController.GetAsync(objectId, currentSessionToken, cancellationToken).OnSuccess(_ => {
{
var filestate = _.Result; var filestate = _.Result;
return new AVFile(filestate); return new AVFile(filestate);
}); });
} }
public static AVFile CreateWithoutData(string objectId) public static AVFile CreateWithoutData(string objectId) {
{
return new AVFile(objectId); return new AVFile(objectId);
} }
public static AVFile CreateWithState(FileState state) public static AVFile CreateWithState(FileState state) {
{
return new AVFile(state); return new AVFile(state);
} }
public static AVFile CreateWithData(string objectId,string name, string url,IDictionary<string,object> metaData) public static AVFile CreateWithData(string objectId, string name, string url, IDictionary<string, object> metaData) {
{
var fileState = new FileState(); var fileState = new FileState();
fileState.Name = name; fileState.Name = name;
fileState.ObjectId = objectId; fileState.ObjectId = objectId;
@ -673,23 +615,18 @@ namespace LeanCloud
/// </summary> /// </summary>
/// <remarks>获取之后并没有实际执行下载只是加载了文件的元信息以及物理地址Url /// <remarks>获取之后并没有实际执行下载只是加载了文件的元信息以及物理地址Url
/// </remarks> /// </remarks>
public static Task<AVFile> GetFileWithObjectIdAsync(string objectId) public static Task<AVFile> GetFileWithObjectIdAsync(string objectId) {
{
return GetFileWithObjectIdAsync(objectId, CancellationToken.None); return GetFileWithObjectIdAsync(objectId, CancellationToken.None);
} }
internal void MergeFromJSON(IDictionary<string, object> jsonData) internal void MergeFromJSON(IDictionary<string, object> jsonData) {
{ lock (this.mutex) {
lock (this.mutex)
{
state.ObjectId = jsonData["objectId"] as string; state.ObjectId = jsonData["objectId"] as string;
state.Url = new Uri(jsonData["url"] as string, UriKind.Absolute); state.Url = new Uri(jsonData["url"] as string, UriKind.Absolute);
if (jsonData.ContainsKey("name")) if (jsonData.ContainsKey("name")) {
{
state.Name = jsonData["name"] as string; state.Name = jsonData["name"] as string;
} }
if (jsonData.ContainsKey("metaData")) if (jsonData.ContainsKey("metaData")) {
{
state.MetaData = jsonData["metaData"] as Dictionary<string, object>; state.MetaData = jsonData["metaData"] as Dictionary<string, object>;
} }
@ -700,32 +637,25 @@ namespace LeanCloud
/// 删除文件 /// 删除文件
/// </summary> /// </summary>
/// <returns>Task</returns> /// <returns>Task</returns>
public Task DeleteAsync() public Task DeleteAsync() {
{
return DeleteAsync(CancellationToken.None); return DeleteAsync(CancellationToken.None);
} }
internal Task DeleteAsync(CancellationToken cancellationToken) internal Task DeleteAsync(CancellationToken cancellationToken) {
{
return taskQueue.Enqueue(toAwait => DeleteAsync(toAwait, cancellationToken), return taskQueue.Enqueue(toAwait => DeleteAsync(toAwait, cancellationToken),
cancellationToken); cancellationToken);
} }
internal Task DeleteAsync(Task toAwait, CancellationToken cancellationToken) internal Task DeleteAsync(Task toAwait, CancellationToken cancellationToken) {
{ if (ObjectId == null) {
if (ObjectId == null)
{
return Task.FromResult(0); return Task.FromResult(0);
} }
string sessionToken = AVUser.CurrentUser.SessionToken; string sessionToken = AVUser.CurrentUser.SessionToken;
return toAwait.OnSuccess(_ => return toAwait.OnSuccess(_ => {
{
return FileController.DeleteAsync(state, sessionToken, cancellationToken); return FileController.DeleteAsync(state, sessionToken, cancellationToken);
}).Unwrap().OnSuccess(_ => { }); }).Unwrap().OnSuccess(_ => { });
} }
#endregion #endregion
} }
} }

View File

@ -108,7 +108,7 @@ namespace LeanCloud {
} }
/// <summary> /// <summary>
/// 手机号 /// 手机号
/// </summary> /// </summary>
[AVFieldName("mobilePhoneNumber")] [AVFieldName("mobilePhoneNumber")]
public string MobilePhoneNumber { public string MobilePhoneNumber {
@ -143,29 +143,31 @@ namespace LeanCloud {
} }
} }
internal async Task SignUpAsync(Task toAwait, CancellationToken cancellationToken) {
await Create(toAwait, cancellationToken);
CurrentUser = this;
}
/// <summary> /// <summary>
/// Signs up a new user. This will create a new AVUser on the server and will also persist the /// 注册新用户,注册成功后将保存为当前用户。必须设置用户名和密码。
/// session on disk so that you can access the user using <see cref="CurrentUser"/>. A username and
/// password must be set before calling SignUpAsync.
/// </summary> /// </summary>
public Task SignUpAsync() { /// <returns></returns>
return SignUpAsync(CancellationToken.None); public async Task SignUpAsync() {
} if (AuthData == null) {
if (string.IsNullOrEmpty(Username)) {
throw new InvalidOperationException("Cannot sign up user with an empty name.");
}
if (string.IsNullOrEmpty(Password)) {
throw new InvalidOperationException("Cannot sign up user with an empty password.");
}
}
if (!string.IsNullOrEmpty(ObjectId)) {
throw new InvalidOperationException("Cannot sign up a user that already exists.");
}
/// <summary> IDictionary<string, IAVFieldOperation> currentOperations = StartSave();
/// Signs up a new user. This will create a new AVUser on the server and will also persist the try {
/// session on disk so that you can access the user using <see cref="CurrentUser"/>. A username and var serverState = await UserController.SignUpAsync(State, currentOperations);
/// password must be set before calling SignUpAsync. HandleSave(serverState);
/// </summary> CurrentUser = this;
/// <param name="cancellationToken">The cancellation token.</param> } catch (Exception) {
public Task SignUpAsync(CancellationToken cancellationToken) { HandleFailedSave(currentOperations);
return taskQueue.Enqueue(toAwait => SignUpAsync(toAwait, cancellationToken), }
cancellationToken);
} }
#region 事件流系统相关 API #region 事件流系统相关 API
@ -187,7 +189,7 @@ namespace LeanCloud {
/// <returns></returns> /// <returns></returns>
public Task FollowAsync(string userObjectId, IDictionary<string, object> data) { public Task FollowAsync(string userObjectId, IDictionary<string, object> data) {
if (data != null) { if (data != null) {
data = this.EncodeForSaving(data); data = EncodeForSaving(data);
} }
var command = new AVCommand { var command = new AVCommand {
Path = $"users/{ObjectId}/friendship/{userObjectId}", Path = $"users/{ObjectId}/friendship/{userObjectId}",
@ -329,21 +331,19 @@ namespace LeanCloud {
/// <summary> /// <summary>
/// 更新用户的密码,需要用户的旧密码 /// 更新用户的密码,需要用户的旧密码
/// </summary> /// </summary>
/// <param name="oldPassword">Old password.</param> /// <param name="oldPassword">旧密码</param>
/// <param name="newPassword">New password.</param> /// <param name="newPassword">新密码</param>
public async Task UpdatePasswordAsync(string oldPassword, string newPassword) { public async Task UpdatePasswordAsync(string oldPassword, string newPassword) {
IObjectState state = await UserController.UpdatePasswordAsync(ObjectId, oldPassword, newPassword); IObjectState state = await UserController.UpdatePasswordAsync(ObjectId, oldPassword, newPassword);
HandleFetchResult(state); HandleFetchResult(state);
} }
/// <summary> /// <summary>
/// Gets the authData for this user. /// 用户数据
/// </summary> /// </summary>
internal IDictionary<string, IDictionary<string, object>> AuthData { internal IDictionary<string, IDictionary<string, object>> AuthData {
get { get {
IDictionary<string, IDictionary<string, object>> authData; if (TryGetValue("authData", out IDictionary<string, IDictionary<string, object>> authData)) {
if (this.TryGetValue<IDictionary<string, IDictionary<string, object>>>(
"authData", out authData)) {
return authData; return authData;
} }
return null; return null;
@ -354,8 +354,7 @@ namespace LeanCloud {
} }
private static IAVAuthenticationProvider GetProvider(string providerName) { private static IAVAuthenticationProvider GetProvider(string providerName) {
IAVAuthenticationProvider provider; if (authProviders.TryGetValue(providerName, out IAVAuthenticationProvider provider)) {
if (authProviders.TryGetValue(providerName, out provider)) {
return provider; return provider;
} }
return null; return null;
@ -407,29 +406,27 @@ namespace LeanCloud {
if (authData == null || provider == null) { if (authData == null || provider == null) {
return; return;
} }
IDictionary<string, object> data; if (authData.TryGetValue(provider.AuthType, out IDictionary<string, object> data)) {
if (authData.TryGetValue(provider.AuthType, out data)) {
restorationSuccess = provider.RestoreAuthentication(data); restorationSuccess = provider.RestoreAuthentication(data);
} }
} }
if (!restorationSuccess) { if (!restorationSuccess) {
this.UnlinkFromAsync(provider.AuthType, CancellationToken.None); UnlinkFromAsync(provider.AuthType, CancellationToken.None);
} }
} }
public Task LinkWithAsync(string authType, IDictionary<string, object> data, CancellationToken cancellationToken) { public Task LinkWithAsync(string authType, IDictionary<string, object> data) {
return taskQueue.Enqueue(toAwait => { AuthData = new Dictionary<string, IDictionary<string, object>> {
AuthData = new Dictionary<string, IDictionary<string, object>>(); [authType] = data
AuthData[authType] = data; };
return SaveAsync(cancellationToken); return SaveAsync();
}, cancellationToken);
} }
public Task LinkWithAsync(string authType, CancellationToken cancellationToken) { public Task LinkWithAsync(string authType, CancellationToken cancellationToken) {
var provider = GetProvider(authType); var provider = GetProvider(authType);
return provider.AuthenticateAsync(cancellationToken) return provider.AuthenticateAsync(cancellationToken)
.OnSuccess(t => LinkWithAsync(authType, t.Result, cancellationToken)) .OnSuccess(t => LinkWithAsync(authType, t.Result))
.Unwrap(); .Unwrap();
} }
@ -437,7 +434,7 @@ namespace LeanCloud {
/// Unlinks a user from a service. /// Unlinks a user from a service.
/// </summary> /// </summary>
public Task UnlinkFromAsync(string authType, CancellationToken cancellationToken) { public Task UnlinkFromAsync(string authType, CancellationToken cancellationToken) {
return LinkWithAsync(authType, null, cancellationToken); return LinkWithAsync(authType, null);
} }
/// <summary> /// <summary>
@ -449,12 +446,8 @@ namespace LeanCloud {
} }
} }
internal static async Task<AVUser> LogInWithAsync(string authType, internal static async Task<AVUser> LogInWithAsync(string authType, IDictionary<string, object> data, bool failOnNotExist) {
IDictionary<string, object> data, var ret = await UserController.LogInAsync(authType, data, failOnNotExist);
bool failOnNotExist,
CancellationToken cancellationToken) {
var ret = await UserController.LogInAsync(authType, data, failOnNotExist, cancellationToken);
AVUser user = FromState<AVUser>(ret, "_User"); AVUser user = FromState<AVUser>(ret, "_User");
user.AuthData = new Dictionary<string, IDictionary<string, object>>(); user.AuthData = new Dictionary<string, IDictionary<string, object>>();
user.AuthData[authType] = data; user.AuthData[authType] = data;
@ -463,17 +456,16 @@ namespace LeanCloud {
return CurrentUser; return CurrentUser;
} }
internal static Task<AVUser> LogInWithAsync(string authType, internal static Task<AVUser> LogInWithAsync(string authType) {
CancellationToken cancellationToken) {
var provider = GetProvider(authType); var provider = GetProvider(authType);
return provider.AuthenticateAsync(cancellationToken) return provider.AuthenticateAsync(CancellationToken.None)
.OnSuccess(authData => LogInWithAsync(authType, authData.Result, false, cancellationToken)) .OnSuccess(authData => LogInWithAsync(authType, authData.Result, false))
.Unwrap(); .Unwrap();
} }
internal static void RegisterProvider(IAVAuthenticationProvider provider) { internal static void RegisterProvider(IAVAuthenticationProvider provider) {
authProviders[provider.AuthType] = provider; authProviders[provider.AuthType] = provider;
var curUser = AVUser.CurrentUser; var curUser = CurrentUser;
if (curUser != null) { if (curUser != null) {
curUser.SynchronizeAuthData(provider); curUser.SynchronizeAuthData(provider);
} }
@ -482,8 +474,8 @@ namespace LeanCloud {
#region 手机号登录 #region 手机号登录
internal static async Task<AVUser> LogInWithParametersAsync(Dictionary<string, object> strs) { internal static async Task<AVUser> LogInWithParametersAsync(Dictionary<string, object> strs) {
var ret = await UserController.LogInWithParametersAsync("login", strs); IObjectState ret = await UserController.LogInWithParametersAsync("login", strs);
var user = CreateWithoutData<AVUser>(null); AVUser user = CreateWithoutData<AVUser>(null);
user.HandleFetchResult(ret); user.HandleFetchResult(ret);
CurrentUser = user; CurrentUser = user;
return CurrentUser; return CurrentUser;
@ -523,7 +515,7 @@ namespace LeanCloud {
/// <param name="mobilePhoneNumber">手机号</param> /// <param name="mobilePhoneNumber">手机号</param>
/// <param name="smsCode">短信验证码</param> /// <param name="smsCode">短信验证码</param>
/// <returns></returns> /// <returns></returns>
public static Task<AVUser> LogInBySmsCodeAsync(string mobilePhoneNumber, string smsCode) { public static Task<AVUser> LogInByMobilePhoneNumberSmsCodeAsync(string mobilePhoneNumber, string smsCode) {
Dictionary<string, object> strs = new Dictionary<string, object> { Dictionary<string, object> strs = new Dictionary<string, object> {
{ "mobilePhoneNumber", mobilePhoneNumber }, { "mobilePhoneNumber", mobilePhoneNumber },
{ "smsCode", smsCode } { "smsCode", smsCode }
@ -532,44 +524,13 @@ namespace LeanCloud {
} }
/// <summary> /// <summary>
/// Requests the login SMS code asynchronous. /// 请求登录短信验证码
/// </summary> /// </summary>
/// <param name="mobilePhoneNumber">The mobile phone number.</param> /// <param name="mobilePhoneNumber">手机号</param>
/// <returns></returns> /// <param name="validateToken">验证码</param>
public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber) {
return RequestLogInSmsCodeAsync(mobilePhoneNumber, CancellationToken.None);
}
/// <summary>
/// Requests the login SMS code asynchronous.
/// </summary>
/// <param name="mobilePhoneNumber">The mobile phone number.</param>
/// <param name="validateToken">Validate token.</param>
/// <returns></returns> /// <returns></returns>
public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, string validateToken) { public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, string validateToken) {
return RequestLogInSmsCodeAsync(mobilePhoneNumber, null, CancellationToken.None); Dictionary<string, object> strs = new Dictionary<string, object> {
}
/// <summary>
/// Requests the login SMS code asynchronous.
/// </summary>
/// <param name="mobilePhoneNumber">The mobile phone number.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, CancellationToken cancellationToken) {
return RequestLogInSmsCodeAsync(mobilePhoneNumber, null, cancellationToken);
}
/// <summary>
/// Requests the login SMS code asynchronous.
/// </summary>
/// <param name="mobilePhoneNumber">The mobile phone number.</param>
/// <param name="validateToken">Validate token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, string validateToken, CancellationToken cancellationToken) {
Dictionary<string, object> strs = new Dictionary<string, object>()
{
{ "mobilePhoneNumber", mobilePhoneNumber }, { "mobilePhoneNumber", mobilePhoneNumber },
}; };
if (String.IsNullOrEmpty(validateToken)) { if (String.IsNullOrEmpty(validateToken)) {
@ -603,87 +564,15 @@ namespace LeanCloud {
#endregion #endregion
#region 手机短信
/// <summary>
/// Send sign up sms code async.
/// </summary>
/// <returns>The sign up sms code async.</returns>
/// <param name="mobilePhoneNumber">Mobile phone number.</param>
public static Task SendSignUpSmsCodeAsync(string mobilePhoneNumber) {
return AVCloud.RequestSMSCodeAsync(mobilePhoneNumber);
}
/// <summary>
/// Sign up by mobile phone async.
/// </summary>
/// <returns>The up by mobile phone async.</returns>
/// <param name="mobilePhoneNumber">Mobile phone number.</param>
/// <param name="smsCode">Sms code.</param>
public static Task<AVUser> SignUpByMobilePhoneAsync(string mobilePhoneNumber, string smsCode) {
return SignUpOrLogInByMobilePhoneAsync(mobilePhoneNumber, smsCode);
}
/// <summary>
/// Send log in sms code async.
/// </summary>
/// <returns>The log in sms code async.</returns>
/// <param name="mobilePhoneNumber">Mobile phone number.</param>
public static Task SendLogInSmsCodeAsync(string mobilePhoneNumber) {
return RequestLogInSmsCodeAsync(mobilePhoneNumber);
}
/// <summary>
/// Log in by mobile phone async.
/// </summary>
/// <returns>The in by mobile phone async.</returns>
/// <param name="mobilePhoneNumber">Mobile phone number.</param>
/// <param name="smsCode">Sms code.</param>
public static Task<AVUser> LogInByMobilePhoneAsync(string mobilePhoneNumber, string smsCode) {
return LogInBySmsCodeAsync(mobilePhoneNumber, smsCode);
}
#endregion
#region 重置密码 #region 重置密码
/// <summary> /// <summary>
/// 请求重置密码,需要传入注册时使用的手机号。 /// 请求重置密码,需要传入注册时使用的手机号。
/// </summary> /// </summary>
/// <param name="mobilePhoneNumber">注册时使用的手机号</param> /// <param name="mobilePhoneNumber">注册时使用的手机号</param>
/// <param name="validateToken">图形验证码</param>
/// <returns></returns> /// <returns></returns>
public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber) { public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, string validateToken = null) {
return RequestPasswordResetBySmsCode(mobilePhoneNumber, null, CancellationToken.None);
}
/// <summary>
/// 请求重置密码,需要传入注册时使用的手机号。
/// </summary>
/// <param name="mobilePhoneNumber">注册时使用的手机号</param>
/// <param name="cancellationToken">cancellationToken</param>
/// <returns></returns>
public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, CancellationToken cancellationToken) {
return RequestPasswordResetBySmsCode(mobilePhoneNumber, null, cancellationToken);
}
/// <summary>
/// 请求重置密码,需要传入注册时使用的手机号。
/// </summary>
/// <param name="mobilePhoneNumber">注册时使用的手机号</param>
/// <param name="validateToken">Validate token.</param>
/// <returns></returns>
public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, string validateToken) {
return RequestPasswordResetBySmsCode(mobilePhoneNumber, validateToken, CancellationToken.None);
}
/// <summary>
/// 请求重置密码,需要传入注册时使用的手机号。
/// </summary>
/// <param name="mobilePhoneNumber">注册时使用的手机号</param>
/// <param name="validateToken">Validate token.</param>
/// <param name="cancellationToken">cancellationToken</param>
/// <returns></returns>
public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, string validateToken, CancellationToken cancellationToken) {
Dictionary<string, object> strs = new Dictionary<string, object> { Dictionary<string, object> strs = new Dictionary<string, object> {
{ "mobilePhoneNumber", mobilePhoneNumber }, { "mobilePhoneNumber", mobilePhoneNumber },
}; };
@ -702,20 +591,9 @@ namespace LeanCloud {
/// 通过验证码重置密码。 /// 通过验证码重置密码。
/// </summary> /// </summary>
/// <param name="newPassword">新密码</param> /// <param name="newPassword">新密码</param>
/// <param name="smsCode">6位数验证码</param> /// <param name="smsCode">6 位数验证码</param>
/// <returns></returns> /// <returns></returns>
public static Task ResetPasswordBySmsCodeAsync(string newPassword, string smsCode) { public static Task ResetPasswordBySmsCodeAsync(string newPassword, string smsCode) {
return ResetPasswordBySmsCodeAsync(newPassword, smsCode, CancellationToken.None);
}
/// <summary>
/// 通过验证码重置密码。
/// </summary>
/// <param name="newPassword">新密码</param>
/// <param name="smsCode">6位数验证码</param>
/// <param name="cancellationToken">cancellationToken</param>
/// <returns></returns>
public static Task ResetPasswordBySmsCodeAsync(string newPassword, string smsCode, CancellationToken cancellationToken) {
Dictionary<string, object> strs = new Dictionary<string, object> { Dictionary<string, object> strs = new Dictionary<string, object> {
{ "password", newPassword } { "password", newPassword }
}; };
@ -786,53 +664,6 @@ namespace LeanCloud {
#endregion #endregion
#region in no-local-storage enviroment
internal Task Create() {
return this.Create(CancellationToken.None);
}
internal Task Create(CancellationToken cancellationToken) {
return taskQueue.Enqueue(toAwait => Create(toAwait, cancellationToken),
cancellationToken);
}
internal Task Create(Task toAwait, CancellationToken cancellationToken) {
if (AuthData == null) {
// TODO (hallucinogen): make an Extension of Task to create Task with exception/canceled.
if (string.IsNullOrEmpty(Username)) {
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
tcs.TrySetException(new InvalidOperationException("Cannot sign up user with an empty name."));
return tcs.Task;
}
if (string.IsNullOrEmpty(Password)) {
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
tcs.TrySetException(new InvalidOperationException("Cannot sign up user with an empty password."));
return tcs.Task;
}
}
if (!string.IsNullOrEmpty(ObjectId)) {
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
tcs.TrySetException(new InvalidOperationException("Cannot sign up a user that already exists."));
return tcs.Task;
}
IDictionary<string, IAVFieldOperation> currentOperations = StartSave();
return toAwait.OnSuccess(_ => {
return UserController.SignUpAsync(State, currentOperations, cancellationToken);
}).Unwrap().ContinueWith(t => {
if (t.IsFaulted || t.IsCanceled) {
HandleFailedSave(currentOperations);
} else {
var serverState = t.Result;
HandleSave(serverState);
}
return t;
}).Unwrap();
}
#endregion
#region AVUser Extension #region AVUser Extension
public IDictionary<string, IDictionary<string, object>> GetAuthData() { public IDictionary<string, IDictionary<string, object>> GetAuthData() {
@ -844,42 +675,32 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <param name="data">OAuth data, like {"accessToken":"xxxxxx"}</param> /// <param name="data">OAuth data, like {"accessToken":"xxxxxx"}</param>
/// <param name="platform">auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc</param> /// <param name="platform">auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc</param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public static Task<AVUser> LogInWithAuthDataAsync(IDictionary<string, object> data, public static Task<AVUser> LogInWithAuthDataAsync(IDictionary<string, object> data, string platform, AVUserAuthDataLogInOption options = null) {
string platform,
AVUserAuthDataLogInOption options = null,
CancellationToken cancellationToken = default(System.Threading.CancellationToken)) {
if (options == null) { if (options == null) {
options = new AVUserAuthDataLogInOption(); options = new AVUserAuthDataLogInOption();
} }
return LogInWithAsync(platform, data, options.FailOnNotExist, cancellationToken); return LogInWithAsync(platform, data, options.FailOnNotExist);
} }
public static Task<AVUser> LogInWithAuthDataAndUnionIdAsync( public static Task<AVUser> LogInWithAuthDataAndUnionIdAsync(
IDictionary<string, object> authData, IDictionary<string, object> authData,
string platform, string platform,
string unionId, string unionId,
AVUserAuthDataLogInOption options = null, AVUserAuthDataLogInOption options = null) {
CancellationToken cancellationToken = default(System.Threading.CancellationToken)) {
if (options == null) { if (options == null) {
options = new AVUserAuthDataLogInOption(); options = new AVUserAuthDataLogInOption();
} }
MergeAuthData(authData, unionId, options); MergeAuthData(authData, unionId, options);
return LogInWithAsync(platform, authData, options.FailOnNotExist, cancellationToken); return LogInWithAsync(platform, authData, options.FailOnNotExist);
} }
public static Task<AVUser> LogInAnonymouslyAsync(CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { public static Task<AVUser> LogInAnonymouslyAsync() {
var data = new Dictionary<string, object> { var data = new Dictionary<string, object> {
{ "id", Guid.NewGuid().ToString() } { "id", Guid.NewGuid().ToString() }
}; };
var options = new AVUserAuthDataLogInOption(); var options = new AVUserAuthDataLogInOption();
return LogInWithAuthDataAsync(data, "anonymous", options, cancellationToken); return LogInWithAuthDataAsync(data, "anonymous", options);
}
[Obsolete("please use LogInWithAuthDataAsync instead.")]
public static Task<AVUser> LogInWithAsync(string authType, IDictionary<string, object> data, CancellationToken cancellationToken) {
return LogInWithAsync(authType, data, false, cancellationToken);
} }
/// <summary> /// <summary>
@ -887,23 +708,21 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <param name="data">OAuth data, like {"accessToken":"xxxxxx"}</param> /// <param name="data">OAuth data, like {"accessToken":"xxxxxx"}</param>
/// <param name="platform">auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc</param> /// <param name="platform">auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc</param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public Task AssociateAuthDataAsync(IDictionary<string, object> data, string platform, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { public Task AssociateAuthDataAsync(IDictionary<string, object> data, string platform) {
return LinkWithAsync(platform, data, cancellationToken); return LinkWithAsync(platform, data);
} }
public Task AssociateAuthDataAndUnionIdAsync( public Task AssociateAuthDataAndUnionIdAsync(
IDictionary<string, object> authData, IDictionary<string, object> authData,
string platform, string platform,
string unionId, string unionId,
AVUserAuthDataLogInOption options = null, AVUserAuthDataLogInOption options = null) {
CancellationToken cancellationToken = default(System.Threading.CancellationToken)) {
if (options == null) { if (options == null) {
options = new AVUserAuthDataLogInOption(); options = new AVUserAuthDataLogInOption();
} }
MergeAuthData(authData, unionId, options); MergeAuthData(authData, unionId, options);
return LinkWithAsync(platform, authData, cancellationToken); return LinkWithAsync(platform, authData);
} }
/// <summary> /// <summary>