diff options
Diffstat (limited to 'Timeline/Services')
-rw-r--r-- | Timeline/Services/QCloudCosService.cs | 71 | ||||
-rw-r--r-- | Timeline/Services/UserService.cs | 42 |
2 files changed, 113 insertions, 0 deletions
diff --git a/Timeline/Services/QCloudCosService.cs b/Timeline/Services/QCloudCosService.cs index f4358714..078dd37b 100644 --- a/Timeline/Services/QCloudCosService.cs +++ b/Timeline/Services/QCloudCosService.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -25,6 +26,14 @@ namespace Timeline.Services Task<bool> IsObjectExists(string bucket, string key); /// <summary> + /// Upload an object use put method. + /// </summary> + /// <param name="bucket">The bucket name.</param> + /// <param name="key">The object key.</param> + /// <param name="data">The data to upload.</param> + Task PutObject(string bucket, string key, byte[] data, string contentType); + + /// <summary> /// Generate a presignated url to access the object. /// </summary> /// <param name="bucket">The bucket name.</param> @@ -229,6 +238,68 @@ namespace Timeline.Services } } + public async Task PutObject(string bucket, string key, byte[] data, string contentType) + { + if (bucket == null) + throw new ArgumentNullException(nameof(bucket)); + if (key == null) + throw new ArgumentNullException(nameof(key)); + if (!ValidateBucketName(bucket)) + throw new ArgumentException($"Bucket name is not valid. Param is {bucket} .", nameof(bucket)); + if (data == null) + throw new ArgumentNullException(nameof(data)); + + var host = GetHost(bucket); + var encodedKey = WebUtility.UrlEncode(key); + var md5 = Convert.ToBase64String(MD5.Create().ComputeHash(data)); + + const string kContentMD5HeaderName = "Content-MD5"; + const string kContentTypeHeaderName = "Content-Type"; + + var httpRequest = new HttpRequestMessage() + { + Method = HttpMethod.Put, + RequestUri = new Uri($"https://{host}/{encodedKey}") + }; + httpRequest.Headers.Host = host; + httpRequest.Headers.Date = DateTimeOffset.Now; + var httpContent = new ByteArrayContent(data); + httpContent.Headers.Add(kContentMD5HeaderName, md5); + httpRequest.Content = httpContent; + + var signedHeaders = new Dictionary<string, string> + { + ["Host"] = host, + [kContentMD5HeaderName] = md5 + }; + + if (contentType != null) + { + httpContent.Headers.Add(kContentTypeHeaderName, contentType); + signedHeaders.Add(kContentTypeHeaderName, contentType); + } + + httpRequest.Headers.TryAddWithoutValidation("Authorization", GenerateSign(GetCredentials(), new RequestInfo + { + Method = "put", + Uri = "/" + encodedKey, + Headers = signedHeaders + }, new TimeDuration(DateTimeOffset.Now, DateTimeOffset.Now.AddMinutes(10)))); + + var client = _httpClientFactory.CreateClient(); + + try + { + var response = await client.SendAsync(httpRequest); + if (!response.IsSuccessStatusCode) + throw new Exception($"Not success status code. {response.ToString()}"); + } + catch (Exception e) + { + _logger.LogError(e, "An error occured when test a cos object existence."); + } + } + public string GenerateObjectGetUrl(string bucket, string key) { if (bucket == null) diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index 4a47ca0f..9ebf2668 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using System; using System.Linq; using System.Threading.Tasks; using Timeline.Entities; @@ -65,6 +66,18 @@ namespace Timeline.Services BadOldPassword } + public enum PutAvatarResult + { + /// <summary> + /// Success to upload avatar. + /// </summary> + Success, + /// <summary> + /// The user does not exists. + /// </summary> + UserNotExists + } + public interface IUserService { /// <summary> @@ -141,7 +154,14 @@ namespace Timeline.Services /// <see cref="ChangePasswordResult.BadOldPassword"/> if old password is wrong.</returns> Task<ChangePasswordResult> ChangePassword(string username, string oldPassword, string newPassword); + /// <summary> + /// Get the true avatar url of a user. + /// </summary> + /// <param name="username">The name of user.</param> + /// <returns>The url if user exists. Null if user does not exist.</returns> Task<string> GetAvatarUrl(string username); + + Task<PutAvatarResult> PutAvatar(string username, byte[] data, string mimeType); } public class UserService : IUserService @@ -301,11 +321,33 @@ namespace Timeline.Services public async Task<string> GetAvatarUrl(string username) { + if (username == null) + throw new ArgumentNullException(nameof(username)); + + if ((await GetUser(username)) == null) + return null; + var exists = await _cosService.IsObjectExists("avatar", username); if (exists) return _cosService.GenerateObjectGetUrl("avatar", username); else return _cosService.GenerateObjectGetUrl("avatar", "__default"); } + + public async Task<PutAvatarResult> PutAvatar(string username, byte[] data, string mimeType) + { + if (username == null) + throw new ArgumentNullException(nameof(username)); + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (mimeType == null) + throw new ArgumentNullException(nameof(mimeType)); + + if ((await GetUser(username)) == null) + return PutAvatarResult.UserNotExists; + + await _cosService.PutObject("avatar", username, data, mimeType); + return PutAvatarResult.Success; + } } } |