diff options
author | crupest <crupest@outlook.com> | 2021-04-28 19:20:40 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-04-28 19:20:40 +0800 |
commit | e16c958e5ba47834dc1624e09ed8e5074a60d1c6 (patch) | |
tree | af8de5669e0ade7d1425d7c5599d438a6cf1c38c /BackEnd/Timeline | |
parent | 29453339a7ba744dc19f730ffbd71d6bff01f25b (diff) | |
download | timeline-e16c958e5ba47834dc1624e09ed8e5074a60d1c6.tar.gz timeline-e16c958e5ba47834dc1624e09ed8e5074a60d1c6.tar.bz2 timeline-e16c958e5ba47834dc1624e09ed8e5074a60d1c6.zip |
refator: ...
Diffstat (limited to 'BackEnd/Timeline')
22 files changed, 424 insertions, 120 deletions
diff --git a/BackEnd/Timeline/Auth/PrincipalExtensions.cs b/BackEnd/Timeline/Auth/PrincipalExtensions.cs index 605f66f6..81c21969 100644 --- a/BackEnd/Timeline/Auth/PrincipalExtensions.cs +++ b/BackEnd/Timeline/Auth/PrincipalExtensions.cs @@ -4,9 +4,23 @@ using Timeline.Services.User; namespace Timeline.Auth
{
- internal static class PrincipalExtensions
+ public static class PrincipalExtensions
{
- internal static bool HasPermission(this ClaimsPrincipal principal, UserPermission permission)
+ public static long? GetUserId(this ClaimsPrincipal? principal)
+ {
+ if (principal is null) return null;
+
+ var claim = principal.FindFirst(ClaimTypes.NameIdentifier);
+ if (claim == null)
+ return null;
+
+ if (long.TryParse(claim.Value, out var value))
+ return value;
+
+ throw new InvalidOperationException(Resource.ExceptionUserIdentifierClaimBadFormat);
+ }
+
+ public static bool HasPermission(this ClaimsPrincipal principal, UserPermission permission)
{
return principal.HasClaim(
claim => claim.Type == AuthenticationConstants.PermissionClaimName && string.Equals(claim.Value, permission.ToString(), StringComparison.OrdinalIgnoreCase));
diff --git a/BackEnd/Timeline/Auth/Resource.Designer.cs b/BackEnd/Timeline/Auth/Resource.Designer.cs index e9ef970e..05394551 100644 --- a/BackEnd/Timeline/Auth/Resource.Designer.cs +++ b/BackEnd/Timeline/Auth/Resource.Designer.cs @@ -61,6 +61,15 @@ namespace Timeline.Auth { }
/// <summary>
+ /// Looks up a localized string similar to User identitifier claim is of bad format..
+ /// </summary>
+ internal static string ExceptionUserIdentifierClaimBadFormat {
+ get {
+ return ResourceManager.GetString("ExceptionUserIdentifierClaimBadFormat", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Token is found in authorization header. Token is {0} ..
/// </summary>
internal static string LogTokenFoundInHeader {
diff --git a/BackEnd/Timeline/Auth/Resource.resx b/BackEnd/Timeline/Auth/Resource.resx index 21f2b2de..88cdbd6b 100644 --- a/BackEnd/Timeline/Auth/Resource.resx +++ b/BackEnd/Timeline/Auth/Resource.resx @@ -117,6 +117,9 @@ <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="ExceptionUserIdentifierClaimBadFormat" xml:space="preserve">
+ <value>User identitifier claim is of bad format.</value>
+ </data>
<data name="LogTokenFoundInHeader" xml:space="preserve">
<value>Token is found in authorization header. Token is {0} .</value>
</data>
diff --git a/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs b/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs index d941013f..e7ffa5c5 100644 --- a/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs +++ b/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs @@ -8,7 +8,6 @@ using Timeline.Models.Validation; using Timeline.Services.Api;
using Timeline.Services.Mapper;
using Timeline.Services.Timeline;
-using Timeline.Services.User;
namespace Timeline.Controllers
{
@@ -21,18 +20,18 @@ namespace Timeline.Controllers {
private readonly IBookmarkTimelineService _service;
private readonly ITimelineService _timelineService;
- private readonly TimelineMapper _timelineMapper;
+ private readonly IGenericMapper _mapper;
- public BookmarkTimelineController(IBookmarkTimelineService service, ITimelineService timelineService, TimelineMapper timelineMapper)
+ public BookmarkTimelineController(IBookmarkTimelineService service, ITimelineService timelineService, IGenericMapper mapper)
{
_service = service;
_timelineService = timelineService;
- _timelineMapper = timelineMapper;
+ _mapper = mapper;
}
private Task<List<HttpTimeline>> Map(List<TimelineEntity> timelines)
{
- return _timelineMapper.MapToHttp(timelines, Url, this.GetOptionalUserId(), this.UserHasPermission(UserPermission.AllTimelineManagement));
+ return _mapper.MapListAsync<HttpTimeline>(timelines, Url, User);
}
/// <summary>
diff --git a/BackEnd/Timeline/Controllers/HighlightTimelineController.cs b/BackEnd/Timeline/Controllers/HighlightTimelineController.cs index 4facc4a1..4e739056 100644 --- a/BackEnd/Timeline/Controllers/HighlightTimelineController.cs +++ b/BackEnd/Timeline/Controllers/HighlightTimelineController.cs @@ -21,18 +21,18 @@ namespace Timeline.Controllers {
private readonly IHighlightTimelineService _service;
private readonly ITimelineService _timelineService;
- private readonly TimelineMapper _timelineMapper;
+ private readonly IGenericMapper _mapper;
- public HighlightTimelineController(IHighlightTimelineService service, ITimelineService timelineService, TimelineMapper timelineMapper)
+ public HighlightTimelineController(IHighlightTimelineService service, ITimelineService timelineService, IGenericMapper mapper)
{
_service = service;
_timelineService = timelineService;
- _timelineMapper = timelineMapper;
+ _mapper = mapper;
}
private Task<List<HttpTimeline>> Map(List<TimelineEntity> timelines)
{
- return _timelineMapper.MapToHttp(timelines, Url, this.GetOptionalUserId(), this.UserHasPermission(UserPermission.AllTimelineManagement));
+ return _mapper.MapListAsync<HttpTimeline>(timelines, Url, User);
}
/// <summary>
diff --git a/BackEnd/Timeline/Controllers/SearchController.cs b/BackEnd/Timeline/Controllers/SearchController.cs index 33e50e59..76f3d8f2 100644 --- a/BackEnd/Timeline/Controllers/SearchController.cs +++ b/BackEnd/Timeline/Controllers/SearchController.cs @@ -7,7 +7,6 @@ using Timeline.Entities; using Timeline.Models.Http;
using Timeline.Services.Api;
using Timeline.Services.Mapper;
-using Timeline.Services.User;
namespace Timeline.Controllers
{
@@ -20,19 +19,17 @@ namespace Timeline.Controllers public class SearchController : Controller
{
private readonly ISearchService _service;
- private readonly TimelineMapper _timelineMapper;
- private readonly UserMapper _userMapper;
+ private readonly IGenericMapper _mapper;
- public SearchController(ISearchService service, TimelineMapper timelineMapper, UserMapper userMapper)
+ public SearchController(ISearchService service, IGenericMapper mapper)
{
_service = service;
- _timelineMapper = timelineMapper;
- _userMapper = userMapper;
+ _mapper = mapper;
}
private Task<List<HttpTimeline>> Map(List<TimelineEntity> timelines)
{
- return _timelineMapper.MapToHttp(timelines, Url, this.GetOptionalUserId(), this.UserHasPermission(UserPermission.AllTimelineManagement));
+ return _mapper.MapListAsync<HttpTimeline>(timelines, Url, User);
}
/// <summary>
@@ -62,7 +59,7 @@ namespace Timeline.Controllers {
var searchResult = await _service.SearchUser(query);
var users = searchResult.Items.Select(i => i.Item).ToList();
- return await _userMapper.MapToHttp(users, Url);
+ return await _mapper.MapListAsync<HttpUser>(users, Url, User);
}
}
}
diff --git a/BackEnd/Timeline/Controllers/TimelineController.cs b/BackEnd/Timeline/Controllers/TimelineController.cs index c6b1f9ad..497d7893 100644 --- a/BackEnd/Timeline/Controllers/TimelineController.cs +++ b/BackEnd/Timeline/Controllers/TimelineController.cs @@ -1,5 +1,4 @@ -using AutoMapper;
-using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
@@ -28,18 +27,15 @@ namespace Timeline.Controllers {
private readonly IUserService _userService;
private readonly ITimelineService _service;
-
- private readonly TimelineMapper _timelineMapper;
- private readonly IMapper _mapper;
+ private readonly IGenericMapper _mapper;
/// <summary>
///
/// </summary>
- public TimelineController(IUserService userService, ITimelineService service, TimelineMapper timelineMapper, IMapper mapper)
+ public TimelineController(IUserService userService, ITimelineService service, IGenericMapper mapper)
{
_userService = userService;
_service = service;
- _timelineMapper = timelineMapper;
_mapper = mapper;
}
@@ -47,12 +43,12 @@ namespace Timeline.Controllers private Task<HttpTimeline> Map(TimelineEntity timeline)
{
- return _timelineMapper.MapToHttp(timeline, Url, this.GetOptionalUserId(), UserHasAllTimelineManagementPermission);
+ return _mapper.MapAsync<HttpTimeline>(timeline, Url, User);
}
private Task<List<HttpTimeline>> Map(List<TimelineEntity> timelines)
{
- return _timelineMapper.MapToHttp(timelines, Url, this.GetOptionalUserId(), UserHasAllTimelineManagementPermission);
+ return _mapper.MapListAsync<HttpTimeline>(timelines, Url, User);
}
/// <summary>
@@ -157,7 +153,7 @@ namespace Timeline.Controllers try
{
- await _service.ChangePropertyAsync(timelineId, _mapper.Map<TimelineChangePropertyParams>(body));
+ await _service.ChangePropertyAsync(timelineId, _mapper.AutoMapperMap<TimelineChangePropertyParams>(body));
var t = await _service.GetTimelineAsync(timelineId);
var result = await Map(t);
return result;
diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index cea873b0..2e1ed3a9 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -31,31 +31,31 @@ namespace Timeline.Controllers private readonly ITimelineService _timelineService;
private readonly ITimelinePostService _postService;
- private readonly TimelineMapper _timelineMapper;
+ private readonly IGenericMapper _mapper;
private readonly MarkdownProcessor _markdownProcessor;
/// <summary>
///
/// </summary>
- public TimelinePostController(ITimelineService timelineService, ITimelinePostService timelinePostService, TimelineMapper timelineMapper, MarkdownProcessor markdownProcessor)
+ public TimelinePostController(ITimelineService timelineService, ITimelinePostService timelinePostService, IGenericMapper mapper, MarkdownProcessor markdownProcessor)
{
_timelineService = timelineService;
_postService = timelinePostService;
- _timelineMapper = timelineMapper;
+ _mapper = mapper;
_markdownProcessor = markdownProcessor;
}
private bool UserHasAllTimelineManagementPermission => this.UserHasPermission(UserPermission.AllTimelineManagement);
- private Task<HttpTimelinePost> Map(TimelinePostEntity post, string timelineName)
+ private Task<HttpTimelinePost> Map(TimelinePostEntity post)
{
- return _timelineMapper.MapToHttp(post, timelineName, Url, this.GetOptionalUserId(), UserHasAllTimelineManagementPermission);
+ return _mapper.MapAsync<HttpTimelinePost>(post, Url, User);
}
- private Task<List<HttpTimelinePost>> Map(List<TimelinePostEntity> posts, string timelineName)
+ private Task<List<HttpTimelinePost>> Map(List<TimelinePostEntity> posts)
{
- return _timelineMapper.MapToHttp(posts, timelineName, Url, this.GetOptionalUserId(), UserHasAllTimelineManagementPermission);
+ return _mapper.MapListAsync<HttpTimelinePost>(posts, Url, User);
}
/// <summary>
@@ -80,7 +80,7 @@ namespace Timeline.Controllers var posts = await _postService.GetPostsAsync(timelineId, modifiedSince, includeDeleted ?? false);
- var result = await Map(posts, timeline);
+ var result = await Map(posts);
return result;
}
@@ -104,7 +104,7 @@ namespace Timeline.Controllers }
var post = await _postService.GetPostAsync(timelineId, postId);
- var result = await Map(post, timeline);
+ var result = await Map(post);
return result;
}
@@ -213,7 +213,7 @@ namespace Timeline.Controllers try
{
var post = await _postService.CreatePostAsync(timelineId, userId, createRequest);
- var result = await Map(post, timeline);
+ var result = await Map(post);
return result;
}
catch (TimelinePostCreateDataException e)
@@ -245,7 +245,7 @@ namespace Timeline.Controllers }
var entity = await _postService.PatchPostAsync(timelineId, post, new TimelinePostPatchRequest { Time = body.Time, Color = body.Color });
- var result = await Map(entity, timeline);
+ var result = await Map(entity);
return Ok(result);
}
diff --git a/BackEnd/Timeline/Controllers/TokenController.cs b/BackEnd/Timeline/Controllers/TokenController.cs index 3b35fa13..e728ae6d 100644 --- a/BackEnd/Timeline/Controllers/TokenController.cs +++ b/BackEnd/Timeline/Controllers/TokenController.cs @@ -25,15 +25,15 @@ namespace Timeline.Controllers {
private readonly IUserTokenManager _userTokenManager;
private readonly ILogger<TokenController> _logger;
- private readonly UserMapper _userMapper;
+ private readonly IGenericMapper _mapper;
private readonly IClock _clock;
/// <summary></summary>
- public TokenController(IUserTokenManager userTokenManager, ILogger<TokenController> logger, UserMapper userMapper, IClock clock)
+ public TokenController(IUserTokenManager userTokenManager, ILogger<TokenController> logger, IGenericMapper mapper, IClock clock)
{
_userTokenManager = userTokenManager;
_logger = logger;
- _userMapper = userMapper;
+ _mapper = mapper;
_clock = clock;
}
@@ -72,7 +72,7 @@ namespace Timeline.Controllers return new HttpCreateTokenResponse
{
Token = result.Token,
- User = await _userMapper.MapToHttp(result.User, Url)
+ User = await _mapper.MapAsync<HttpUser>(result.User, Url, User)
};
}
catch (UserNotExistException e)
@@ -113,7 +113,7 @@ namespace Timeline.Controllers ("Username", result.Username), ("Token", request.Token)));
return new HttpVerifyTokenResponse
{
- User = await _userMapper.MapToHttp(result, Url)
+ User = await _mapper.MapAsync<HttpUser>(result, Url, User)
};
}
catch (UserTokenTimeExpiredException e)
diff --git a/BackEnd/Timeline/Controllers/UserController.cs b/BackEnd/Timeline/Controllers/UserController.cs index 38d5d70c..615eac2d 100644 --- a/BackEnd/Timeline/Controllers/UserController.cs +++ b/BackEnd/Timeline/Controllers/UserController.cs @@ -1,4 +1,3 @@ -using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -28,17 +27,15 @@ namespace Timeline.Controllers private readonly IUserService _userService;
private readonly IUserPermissionService _userPermissionService;
private readonly IUserDeleteService _userDeleteService;
- private readonly UserMapper _userMapper;
- private readonly IMapper _mapper;
+ private readonly IGenericMapper _mapper;
/// <summary></summary>
- public UserController(ILogger<UserController> logger, IUserService userService, IUserPermissionService userPermissionService, IUserDeleteService userDeleteService, UserMapper userMapper, IMapper mapper)
+ public UserController(ILogger<UserController> logger, IUserService userService, IUserPermissionService userPermissionService, IUserDeleteService userDeleteService, IGenericMapper mapper)
{
_logger = logger;
_userService = userService;
_userPermissionService = userPermissionService;
_userDeleteService = userDeleteService;
- _userMapper = userMapper;
_mapper = mapper;
}
@@ -53,7 +50,7 @@ namespace Timeline.Controllers public async Task<ActionResult<List<HttpUser>>> List()
{
var users = await _userService.GetUsersAsync();
- var result = await _userMapper.MapToHttp(users, Url);
+ var result = await _mapper.MapListAsync<HttpUser>(users, Url, User);
return result;
}
@@ -72,7 +69,7 @@ namespace Timeline.Controllers {
var user = await _userService.CreateUserAsync(
new CreateUserParams(body.Username, body.Password) { Nickname = body.Nickname });
- return await _userMapper.MapToHttp(user, Url);
+ return await _mapper.MapAsync<HttpUser>(user, Url, User);
}
catch (EntityAlreadyExistException e) when (e.EntityName == EntityNames.User)
{
@@ -94,7 +91,7 @@ namespace Timeline.Controllers {
var id = await _userService.GetUserIdByUsernameAsync(username);
var user = await _userService.GetUserAsync(id);
- return await _userMapper.MapToHttp(user, Url);
+ return await _mapper.MapAsync<HttpUser>(user, Url, User);
}
catch (UserNotExistException e)
{
@@ -122,8 +119,8 @@ namespace Timeline.Controllers try
{
var id = await _userService.GetUserIdByUsernameAsync(username);
- var user = await _userService.ModifyUserAsync(id, _mapper.Map<ModifyUserParams>(body));
- return await _userMapper.MapToHttp(user, Url);
+ var user = await _userService.ModifyUserAsync(id, _mapper.AutoMapperMap<ModifyUserParams>(body));
+ return await _mapper.MapAsync<HttpUser>(user, Url, User);
}
catch (UserNotExistException e)
{
@@ -149,8 +146,8 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden,
ErrorResponse.Common.CustomMessage_Forbid(UserController_Patch_Forbid_Password));
- var user = await _userService.ModifyUserAsync(this.GetUserId(), _mapper.Map<ModifyUserParams>(body));
- return await _userMapper.MapToHttp(user, Url);
+ var user = await _userService.ModifyUserAsync(this.GetUserId(), _mapper.AutoMapperMap<ModifyUserParams>(body));
+ return await _mapper.MapAsync<HttpUser>(user, Url, User);
}
}
diff --git a/BackEnd/Timeline/Services/Mapper/GenericMapper.cs b/BackEnd/Timeline/Services/Mapper/GenericMapper.cs new file mode 100644 index 00000000..4dd44828 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/GenericMapper.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ class GenericMapper : IGenericMapper
+ {
+ private readonly IServiceProvider _serviceProvider;
+ private readonly AutoMapper.IMapper _autoMapper;
+
+ public GenericMapper(IServiceProvider serviceProvider, AutoMapper.IMapper autoMapper)
+ {
+ _serviceProvider = serviceProvider;
+ _autoMapper = autoMapper;
+ }
+
+ public TDestination AutoMapperMap<TDestination>(object source)
+ {
+ return _autoMapper.Map<TDestination>(source);
+ }
+
+ public async Task<TDestination> MapAsync<TSource, TDestination>(TSource source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var mapper = _serviceProvider.GetService<IMapper<TSource, TDestination>>();
+
+ if (mapper is not null)
+ {
+ return await mapper.MapAsync(source, urlHelper, user);
+ }
+
+ return _autoMapper.Map<TSource, TDestination>(source);
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/IGenericMapper.cs b/BackEnd/Timeline/Services/Mapper/IGenericMapper.cs new file mode 100644 index 00000000..2583f036 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/IGenericMapper.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ public interface IGenericMapper
+ {
+ TDestination AutoMapperMap<TDestination>(object source);
+ Task<TDestination> MapAsync<TSource, TDestination>(TSource source, IUrlHelper urlHelper, ClaimsPrincipal? user);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/IMapper.cs b/BackEnd/Timeline/Services/Mapper/IMapper.cs new file mode 100644 index 00000000..ef1b619f --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/IMapper.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ public interface IMapper<TSource, TDestination>
+ {
+ Task<TDestination> MapAsync(TSource source, IUrlHelper urlHelper, ClaimsPrincipal? user);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/MapperExtensions.cs b/BackEnd/Timeline/Services/Mapper/MapperExtensions.cs new file mode 100644 index 00000000..03dd1189 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/MapperExtensions.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ public static class MapperExtensions
+ {
+ public static async Task<List<TDestination>> MapListAsync<TSource, TDestination>(this IMapper<TSource, TDestination> mapper, IEnumerable<TSource> source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var result = new List<TDestination>();
+ foreach (var s in source)
+ {
+ result.Add(await mapper.MapAsync(s, urlHelper, user));
+ }
+ return result;
+ }
+
+ public static Task<TDestination> MapAsync<TDestination>(this IGenericMapper mapper, object source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var method = typeof(IGenericMapper).GetMethod(nameof(IGenericMapper.MapAsync));
+ var m = method!.MakeGenericMethod(source.GetType(), typeof(TDestination))!;
+ return (Task<TDestination>)m.Invoke(mapper, new object?[] { source, urlHelper, user })!;
+ }
+
+ public static async Task<List<TDestination>> MapListAsync<TSource, TDestination>(this IGenericMapper mapper, IEnumerable<TSource> source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var result = new List<TDestination>();
+ foreach (var s in source)
+ {
+ result.Add(await mapper.MapAsync<TSource, TDestination>(s, urlHelper, user));
+ }
+ return result;
+ }
+
+ public static async Task<List<TDestination>> MapListAsync<TDestination>(this IGenericMapper mapper, IEnumerable<object> source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var result = new List<TDestination>();
+ foreach (var s in source)
+ {
+ result.Add(await mapper.MapAsync<TDestination>(s, urlHelper, user));
+ }
+ return result;
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs index 262b2f20..0c2d0cfd 100644 --- a/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs +++ b/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs @@ -1,4 +1,6 @@ using Microsoft.Extensions.DependencyInjection;
+using Timeline.Entities;
+using Timeline.Models.Http;
namespace Timeline.Services.Mapper
{
@@ -6,8 +8,11 @@ namespace Timeline.Services.Mapper {
public static void AddMappers(this IServiceCollection services)
{
- services.AddScoped<UserMapper, UserMapper>();
- services.AddScoped<TimelineMapper, TimelineMapper>();
+ services.AddAutoMapper(typeof(Startup).Assembly);
+ services.AddScoped<IMapper<UserEntity, HttpUser>, UserMapper>();
+ services.AddScoped<IMapper<TimelineEntity, HttpTimeline>, TimelineMapper>();
+ services.AddScoped<IMapper<TimelinePostEntity, HttpTimelinePost>, TimelineMapper>();
+ services.AddScoped<IGenericMapper, GenericMapper>();
}
}
}
diff --git a/BackEnd/Timeline/Services/Mapper/Resource.Designer.cs b/BackEnd/Timeline/Services/Mapper/Resource.Designer.cs new file mode 100644 index 00000000..71aab793 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/Resource.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Timeline.Services.Mapper {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resource {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resource() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Services.Mapper.Resource", typeof(Resource).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to This map is unsupported by this map provider..
+ /// </summary>
+ internal static string ExceptionUnsupportedMap {
+ get {
+ return ResourceManager.GetString("ExceptionUnsupportedMap", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/Resource.resx b/BackEnd/Timeline/Services/Mapper/Resource.resx new file mode 100644 index 00000000..f075c1bb --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/Resource.resx @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="ExceptionUnsupportedMap" xml:space="preserve">
+ <value>This map is unsupported by this map provider.</value>
+ </data>
+</root>
\ No newline at end of file diff --git a/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs b/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs index c8279b42..5ee90a8f 100644 --- a/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs +++ b/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs @@ -2,25 +2,29 @@ using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
+using System.Security.Claims;
using System.Threading.Tasks;
+using Timeline.Auth;
using Timeline.Controllers;
using Timeline.Entities;
using Timeline.Models.Http;
using Timeline.Services.Api;
using Timeline.Services.Timeline;
+using Timeline.Services.User;
namespace Timeline.Services.Mapper
{
- public class TimelineMapper
+ public class TimelineMapper : IMapper<TimelineEntity, HttpTimeline>,
+ IMapper<TimelinePostEntity, HttpTimelinePost>
{
private readonly DatabaseContext _database;
- private readonly UserMapper _userMapper;
+ private readonly IMapper<UserEntity, HttpUser> _userMapper;
private readonly IHighlightTimelineService _highlightTimelineService;
private readonly IBookmarkTimelineService _bookmarkTimelineService;
private readonly ITimelineService _timelineService;
private readonly ITimelinePostService _timelinePostService;
- public TimelineMapper(DatabaseContext database, UserMapper userMapper, IHighlightTimelineService highlightTimelineService, IBookmarkTimelineService bookmarkTimelineService, ITimelineService timelineService, ITimelinePostService timelinePostService)
+ public TimelineMapper(DatabaseContext database, IMapper<UserEntity, HttpUser> userMapper, IHighlightTimelineService highlightTimelineService, IBookmarkTimelineService bookmarkTimelineService, ITimelineService timelineService, ITimelinePostService timelinePostService)
{
_database = database;
_userMapper = userMapper;
@@ -30,20 +34,27 @@ namespace Timeline.Services.Mapper _timelinePostService = timelinePostService;
}
- public async Task<HttpTimeline> MapToHttp(TimelineEntity entity, IUrlHelper urlHelper, long? userId, bool isAdministrator)
+ private string CalculateTimelineName(TimelineEntity entity)
{
+ return entity.Name is null ? "@" + entity.Owner.Username : entity.Name;
+ }
+
+ public async Task<HttpTimeline> MapAsync(TimelineEntity entity, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var userId = user.GetUserId();
+
await _database.Entry(entity).Reference(e => e.Owner).LoadAsync();
await _database.Entry(entity).Collection(e => e.Members).Query().Include(m => m.User).LoadAsync();
- var timelineName = entity.Name is null ? "@" + entity.Owner.Username : entity.Name;
+ var timelineName = CalculateTimelineName(entity);
bool manageable;
- if (userId is null)
+ if (user is null || userId is null)
{
manageable = false;
}
- else if (isAdministrator)
+ else if (user.HasPermission(UserPermission.AllTimelineManagement))
{
manageable = true;
}
@@ -53,7 +64,7 @@ namespace Timeline.Services.Mapper }
bool postable;
- if (userId is null)
+ if (user is null || userId is null)
{
postable = false;
}
@@ -68,9 +79,9 @@ namespace Timeline.Services.Mapper name: timelineName,
nameLastModifed: entity.NameLastModified,
description: entity.Description ?? "",
- owner: await _userMapper.MapToHttp(entity.Owner, urlHelper),
+ owner: await _userMapper.MapAsync(entity.Owner, urlHelper, user),
visibility: entity.Visibility,
- members: await _userMapper.MapToHttp(entity.Members.Select(m => m.User).ToList(), urlHelper),
+ members: await _userMapper.MapListAsync(entity.Members.Select(m => m.User).ToList(), urlHelper, user),
color: entity.Color,
createTime: entity.CreateTime,
lastModified: entity.LastModified,
@@ -85,39 +96,31 @@ namespace Timeline.Services.Mapper );
}
- public async Task<List<HttpTimeline>> MapToHttp(List<TimelineEntity> entities, IUrlHelper urlHelper, long? userId, bool isAdministrator)
- {
- var result = new List<HttpTimeline>();
- foreach (var entity in entities)
- {
- result.Add(await MapToHttp(entity, urlHelper, userId, isAdministrator));
- }
- return result;
- }
-
- public async Task<HttpTimelinePost> MapToHttp(TimelinePostEntity entity, string timelineName, IUrlHelper urlHelper, long? userId, bool isAdministrator)
+ public async Task<HttpTimelinePost> MapAsync(TimelinePostEntity entity, IUrlHelper urlHelper, ClaimsPrincipal? user)
{
- _ = timelineName;
+ var userId = user.GetUserId();
+ await _database.Entry(entity).Reference(e => e.Timeline).LoadAsync();
await _database.Entry(entity).Collection(p => p.DataList).LoadAsync();
await _database.Entry(entity).Reference(e => e.Author).LoadAsync();
+ await _database.Entry(entity.Timeline).Reference(e => e.Owner).LoadAsync();
List<HttpTimelinePostDataDigest> dataDigestList = entity.DataList.OrderBy(d => d.Index).Select(d => new HttpTimelinePostDataDigest(d.Kind, $"\"{d.DataTag}\"", d.LastUpdated)).ToList();
HttpUser? author = null;
if (entity.Author is not null)
{
- author = await _userMapper.MapToHttp(entity.Author, urlHelper);
+ author = await _userMapper.MapAsync(entity.Author, urlHelper, user);
}
bool editable;
- if (userId is null)
+ if (user is null || userId is null)
{
editable = false;
}
- else if (isAdministrator)
+ else if (user.HasPermission(UserPermission.AllTimelineManagement))
{
editable = true;
}
@@ -126,7 +129,6 @@ namespace Timeline.Services.Mapper editable = await _timelinePostService.HasPostModifyPermissionAsync(entity.TimelineId, entity.LocalId, userId.Value);
}
-
return new HttpTimelinePost(
id: entity.LocalId,
dataList: dataDigestList,
@@ -135,24 +137,9 @@ namespace Timeline.Services.Mapper color: entity.Color,
deleted: entity.Deleted,
lastUpdated: entity.LastUpdated,
- timelineName: timelineName,
+ timelineName: CalculateTimelineName(entity.Timeline),
editable: editable
);
}
-
- public async Task<List<HttpTimelinePost>> MapToHttp(List<TimelinePostEntity> entities, string timelineName, IUrlHelper urlHelper, long? userId, bool isAdministrator)
- {
- var result = new List<HttpTimelinePost>();
- foreach (var entity in entities)
- {
- result.Add(await MapToHttp(entity, timelineName, urlHelper, userId, isAdministrator));
- }
- return result;
- }
-
- internal Task MapToHttp(TimelinePostEntity post, string timeline, IUrlHelper url)
- {
- throw new System.NotImplementedException();
- }
}
}
diff --git a/BackEnd/Timeline/Services/Mapper/UserMapper.cs b/BackEnd/Timeline/Services/Mapper/UserMapper.cs index 42f88d8a..8855eef2 100644 --- a/BackEnd/Timeline/Services/Mapper/UserMapper.cs +++ b/BackEnd/Timeline/Services/Mapper/UserMapper.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc;
-using System.Collections.Generic;
+using System.Security.Claims;
using System.Threading.Tasks;
using Timeline.Controllers;
using Timeline.Entities;
@@ -8,7 +8,7 @@ using Timeline.Services.User; namespace Timeline.Services.Mapper
{
- public class UserMapper
+ public class UserMapper : IMapper<UserEntity, HttpUser>
{
private readonly DatabaseContext _database;
private readonly IUserPermissionService _userPermissionService;
@@ -19,7 +19,7 @@ namespace Timeline.Services.Mapper _userPermissionService = userPermissionService;
}
- public async Task<HttpUser> MapToHttp(UserEntity entity, IUrlHelper urlHelper)
+ public async Task<HttpUser> MapAsync(UserEntity entity, IUrlHelper urlHelper, ClaimsPrincipal? user)
{
return new HttpUser(
uniqueId: entity.UniqueId,
@@ -33,15 +33,5 @@ namespace Timeline.Services.Mapper )
);
}
-
- public async Task<List<HttpUser>> MapToHttp(List<UserEntity> entities, IUrlHelper urlHelper)
- {
- var result = new List<HttpUser>();
- foreach (var entity in entities)
- {
- result.Add(await MapToHttp(entity, urlHelper));
- }
- return result;
- }
}
}
diff --git a/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs index 556800df..97b313cd 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs @@ -1,9 +1,5 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace Timeline.Services.Timeline
{
diff --git a/BackEnd/Timeline/Startup.cs b/BackEnd/Timeline/Startup.cs index b944b99b..994dd7bf 100644 --- a/BackEnd/Timeline/Startup.cs +++ b/BackEnd/Timeline/Startup.cs @@ -86,8 +86,6 @@ namespace Timeline services.AddAuthorization();
services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
- services.AddAutoMapper(GetType().Assembly);
- services.AddMappers();
services.AddDbContext<DatabaseContext>((services, options) =>
{
@@ -104,6 +102,8 @@ namespace Timeline services.AddTimelineServices();
+ services.AddMappers();
+
services.AddScoped<IHighlightTimelineService, HighlightTimelineService>();
services.AddScoped<IBookmarkTimelineService, BookmarkTimelineService>();
services.AddScoped<ISearchService, SearchService>();
diff --git a/BackEnd/Timeline/Timeline.csproj b/BackEnd/Timeline/Timeline.csproj index 3ddcecaf..3c2f3b85 100644 --- a/BackEnd/Timeline/Timeline.csproj +++ b/BackEnd/Timeline/Timeline.csproj @@ -148,6 +148,11 @@ <AutoGen>True</AutoGen>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
+ <Compile Update="Services\Mapper\Resource.Designer.cs">
+ <DesignTime>True</DesignTime>
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Resource.resx</DependentUpon>
+ </Compile>
<Compile Update="Services\Resource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
@@ -257,6 +262,10 @@ <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
+ <EmbeddedResource Update="Services\Mapper\Resource.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resource.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
<EmbeddedResource Update="Services\Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|