From 3bc8ee1de171f0bd8e226542d75c842c5b2e7175 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 24 Apr 2022 15:22:05 +0800 Subject: ... --- .../Controllers/BookmarkTimelineController.cs | 2 ++ .../Controllers/HighlightTimelineController.cs | 2 ++ BackEnd/Timeline/Controllers/TimelineController.cs | 1 + .../Timeline/Controllers/TimelinePostController.cs | 5 +-- BackEnd/Timeline/Controllers/TokenController.cs | 1 + .../Timeline/Controllers/UserAvatarController.cs | 2 ++ BackEnd/Timeline/Controllers/UserController.cs | 5 +-- .../Controllers/V2/TimelinePostV2Controller.cs | 6 ++-- .../Services/Timeline/MarkdownProcessor.cs | 24 ++++++++++++-- BackEnd/Timeline/SignalRHub/ITimelineClient.cs | 5 ++- BackEnd/Timeline/SignalRHub/TimelineHub.cs | 38 ++++++++++++++++++++++ FrontEnd/src/services/timeline.ts | 20 ++++++++---- FrontEnd/src/views/timeline/Timeline.tsx | 7 ++-- FrontEnd/src/views/timeline/index.tsx | 3 -- 14 files changed, 100 insertions(+), 21 deletions(-) diff --git a/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs b/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs index a1fa511c..ba19e67d 100644 --- a/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs +++ b/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using System; using System.Collections.Generic; using System.Threading.Tasks; using Timeline.Entities; @@ -16,6 +17,7 @@ namespace Timeline.Controllers /// [ApiController] [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Use v2 api.")] public class BookmarkTimelineController : MyControllerBase { private readonly IBookmarkTimelineService _service; diff --git a/BackEnd/Timeline/Controllers/HighlightTimelineController.cs b/BackEnd/Timeline/Controllers/HighlightTimelineController.cs index e30cf720..94fdd01e 100644 --- a/BackEnd/Timeline/Controllers/HighlightTimelineController.cs +++ b/BackEnd/Timeline/Controllers/HighlightTimelineController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using System; using System.Collections.Generic; using System.Threading.Tasks; using Timeline.Auth; @@ -17,6 +18,7 @@ namespace Timeline.Controllers /// [ApiController] [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Use v2 bookmark instead.")] public class HighlightTimelineController : MyControllerBase { private readonly IHighlightTimelineService _service; diff --git a/BackEnd/Timeline/Controllers/TimelineController.cs b/BackEnd/Timeline/Controllers/TimelineController.cs index 7aeec02f..4a3bdbe1 100644 --- a/BackEnd/Timeline/Controllers/TimelineController.cs +++ b/BackEnd/Timeline/Controllers/TimelineController.cs @@ -23,6 +23,7 @@ namespace Timeline.Controllers [Route("timelines")] [CatchMultipleTimelineException] [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Ues v2 api.")] public class TimelineController : MyControllerBase { private readonly IUserService _userService; diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index fee80adb..ee457a1b 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -26,7 +26,8 @@ namespace Timeline.Controllers [ApiController] [Route("timelines/{timeline}/posts")] [CatchMultipleTimelineException] - [ProducesErrorResponseType(typeof(CommonResponse))] + [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Use v2 api.")] public class TimelinePostController : MyControllerBase { private readonly ILogger _logger; @@ -145,7 +146,7 @@ namespace Timeline.Controllers [ProducesResponseType(typeof(void), StatusCodes.Status304NotModified)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DataGet([FromRoute][GeneralTimelineName] string timeline, [FromRoute] long post, [FromRoute(Name = "data_index")][Range(0, 100)] long dataIndex) { var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); diff --git a/BackEnd/Timeline/Controllers/TokenController.cs b/BackEnd/Timeline/Controllers/TokenController.cs index 7fba0bc5..2078c0ec 100644 --- a/BackEnd/Timeline/Controllers/TokenController.cs +++ b/BackEnd/Timeline/Controllers/TokenController.cs @@ -17,6 +17,7 @@ namespace Timeline.Controllers [Route("token")] [ApiController] [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Ues v2 api.")] public class TokenController : MyControllerBase { private readonly IUserService _userService; diff --git a/BackEnd/Timeline/Controllers/UserAvatarController.cs b/BackEnd/Timeline/Controllers/UserAvatarController.cs index 072ab621..9e081757 100644 --- a/BackEnd/Timeline/Controllers/UserAvatarController.cs +++ b/BackEnd/Timeline/Controllers/UserAvatarController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using System; using System.Threading.Tasks; using Timeline.Filters; using Timeline.Helpers.Cache; @@ -17,6 +18,7 @@ namespace Timeline.Controllers /// [ApiController] [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Ues v2 api.")] public class UserAvatarController : MyControllerBase { private readonly IUserService _userService; diff --git a/BackEnd/Timeline/Controllers/UserController.cs b/BackEnd/Timeline/Controllers/UserController.cs index 95a99a03..5dbd7016 100644 --- a/BackEnd/Timeline/Controllers/UserController.cs +++ b/BackEnd/Timeline/Controllers/UserController.cs @@ -1,13 +1,13 @@ -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using System; using System.Collections.Generic; using System.Threading.Tasks; using Timeline.Auth; using Timeline.Filters; using Timeline.Models.Http; using Timeline.Models.Validation; -using Timeline.Services; using Timeline.Services.Mapper; using Timeline.Services.User; @@ -18,6 +18,7 @@ namespace Timeline.Controllers /// [ApiController] [ProducesErrorResponseType(typeof(CommonResponse))] + [Obsolete("Ues v2 api.")] public class UserController : MyControllerBase { private readonly IUserService _userService; diff --git a/BackEnd/Timeline/Controllers/V2/TimelinePostV2Controller.cs b/BackEnd/Timeline/Controllers/V2/TimelinePostV2Controller.cs index 4d486041..8b7101e4 100644 --- a/BackEnd/Timeline/Controllers/V2/TimelinePostV2Controller.cs +++ b/BackEnd/Timeline/Controllers/V2/TimelinePostV2Controller.cs @@ -107,7 +107,7 @@ namespace Timeline.Controllers.V2 var data = await _postService.GetPostDataV2Async(timelineId, post, dataIndex); if (data.ContentType == MimeTypes.TextMarkdown) { - return new ByteData(_markdownProcessor.Process(data.Data, Url, timeline, post), data.ContentType); + return new ByteData(_markdownProcessor.Process(data.Data, Url, owner, timeline, post), data.ContentType); } return data; } @@ -157,8 +157,8 @@ namespace Timeline.Controllers.V2 { var post = await _postService.CreatePostAsync(timelineId, GetAuthUserId(), createRequest); - var group = TimelineHub.GenerateTimelinePostChangeListeningGroupName(timeline); - await _timelineHubContext.Clients.Group(group).SendAsync(nameof(ITimelineClient.OnTimelinePostChanged), timeline); + var group = TimelineHub.GenerateTimelinePostChangeListeningGroupName(owner, timeline); + await _timelineHubContext.Clients.Group(group).SendAsync(nameof(ITimelineClient.OnTimelinePostChangedV2), timeline); var result = await MapAsync(post); return CreatedAtAction("Get", new { owner = owner, timeline = timeline, post = post.LocalId }, result); diff --git a/BackEnd/Timeline/Services/Timeline/MarkdownProcessor.cs b/BackEnd/Timeline/Services/Timeline/MarkdownProcessor.cs index ef8022c0..84b99915 100644 --- a/BackEnd/Timeline/Services/Timeline/MarkdownProcessor.cs +++ b/BackEnd/Timeline/Services/Timeline/MarkdownProcessor.cs @@ -1,4 +1,4 @@ -using Markdig; +using Markdig; using Markdig.Renderers.Normalize; using Markdig.Syntax; using Markdig.Syntax.Inlines; @@ -8,7 +8,7 @@ using System.IO; using System.Linq; using System.Text; using Timeline.Controllers; - + namespace Timeline.Services.Timeline { public class MarkdownProcessor @@ -31,6 +31,7 @@ namespace Timeline.Services.Timeline return writer.ToString(); } + [Obsolete("Use overload with 'owner'.")] /// Convert data url to true url with post id. public string Process(string text, IUrlHelper url, string timeline, long post) { @@ -44,9 +45,28 @@ namespace Timeline.Services.Timeline ); } + [Obsolete("Use overload with 'owner'.")] public byte[] Process(byte[] data, IUrlHelper url, string timeline, long post) { return Encoding.UTF8.GetBytes(Process(Encoding.UTF8.GetString(data), url, timeline, post)); + } + + /// Convert data url to true url with post id. + public string Process(string text, IUrlHelper url, string owner, string timeline, long post) + { + return Process( + text, + dataIndex => url.ActionLink( + "DataGet", + "TimelinePostV2", + new { owner, timeline, post, data_index = dataIndex } + )! + ); + } + + public byte[] Process(byte[] data, IUrlHelper url, string owner, string timeline, long post) + { + return Encoding.UTF8.GetBytes(Process(Encoding.UTF8.GetString(data), url, owner, timeline, post)); } } } diff --git a/BackEnd/Timeline/SignalRHub/ITimelineClient.cs b/BackEnd/Timeline/SignalRHub/ITimelineClient.cs index 0d1be093..675643aa 100644 --- a/BackEnd/Timeline/SignalRHub/ITimelineClient.cs +++ b/BackEnd/Timeline/SignalRHub/ITimelineClient.cs @@ -1,9 +1,12 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace Timeline.SignalRHub { public interface ITimelineClient { + [Obsolete("Use v2.")] Task OnTimelinePostChanged(string timelineName); + Task OnTimelinePostChangedV2(string owner, string timeline); } } diff --git a/BackEnd/Timeline/SignalRHub/TimelineHub.cs b/BackEnd/Timeline/SignalRHub/TimelineHub.cs index 0bfda84c..1925a992 100644 --- a/BackEnd/Timeline/SignalRHub/TimelineHub.cs +++ b/BackEnd/Timeline/SignalRHub/TimelineHub.cs @@ -20,11 +20,18 @@ namespace Timeline.SignalRHub _timelineService = timelineService; } + [Obsolete("Use overload with owner.")] public static string GenerateTimelinePostChangeListeningGroupName(string timelineName) { return $"timeline-post-change-{timelineName}"; + } + + public static string GenerateTimelinePostChangeListeningGroupName(string owner, string timeline) + { + return $"v2-timeline-post-change-{owner}/{timeline}"; } + [Obsolete("Use v2.")] public async Task SubscribeTimelinePostChange(string timelineName) { try @@ -48,11 +55,42 @@ namespace Timeline.SignalRHub } } + public async Task SubscribeTimelinePostChangeV2(string owner, string timeline) + { + try + { + var timelineId = await _timelineService.GetTimelineIdAsync(owner, timeline); + var user = Context.User; + if (!user.HasPermission(UserPermission.AllTimelineManagement) && !await _timelineService.HasReadPermissionAsync(timelineId, user.GetOptionalUserId())) + throw new HubException(Resource.MessageForbidden); + + var group = GenerateTimelinePostChangeListeningGroupName(owner, timeline); + await Groups.AddToGroupAsync(Context.ConnectionId, group); + _logger.LogInformation(Resource.LogSubscribeTimelinePostChange, Context.ConnectionId, group); + } + catch (ArgumentException) + { + throw new HubException(Resource.MessageTimelineNameInvalid); + } + catch (EntityNotExistException) + { + throw new HubException(Resource.MessageTimelineNotExist); + } + } + + [Obsolete("Use v2.")] public async Task UnsubscribeTimelinePostChange(string timelineName) { var group = GenerateTimelinePostChangeListeningGroupName(timelineName); await Groups.RemoveFromGroupAsync(Context.ConnectionId, group); _logger.LogInformation(Resource.LogUnsubscribeTimelinePostChange, Context.ConnectionId, group); + } + + public async Task UnsubscribeTimelinePostChangeV2(string owner, string timeline) + { + var group = GenerateTimelinePostChangeListeningGroupName(owner, timeline); + await Groups.RemoveFromGroupAsync(Context.ConnectionId, group); + _logger.LogInformation(Resource.LogUnsubscribeTimelinePostChange, Context.ConnectionId, group); } } } diff --git a/FrontEnd/src/services/timeline.ts b/FrontEnd/src/services/timeline.ts index d8c0ae00..cb5b1e32 100644 --- a/FrontEnd/src/services/timeline.ts +++ b/FrontEnd/src/services/timeline.ts @@ -21,7 +21,8 @@ export const timelineVisibilityTooltipTranslationMap: Record< }; export function getTimelinePostUpdate$( - timelineName: string + owner: string, + timeline: string ): Observable<{ update: boolean; state: HubConnectionState }> { return new Observable((subscriber) => { subscriber.next({ @@ -37,8 +38,11 @@ export function getTimelinePostUpdate$( .withAutomaticReconnect() .build(); - const handler = (tn: string): void => { - if (timelineName === tn) { + const o = owner; + const t = timeline; + + const handler = (owner: string, timeline: string): void => { + if (owner === o && timeline === t) { subscriber.next({ update: true, state: connection.state }); } }; @@ -64,12 +68,16 @@ export function getTimelinePostUpdate$( }); }); - connection.on("OnTimelinePostChanged", handler); + connection.on("OnTimelinePostChangedV2", handler); void connection.start().then(() => { subscriber.next({ update: false, state: HubConnectionState.Connected }); - return connection.invoke("SubscribeTimelinePostChange", timelineName); + return connection.invoke( + "SubscribeTimelinePostChangeV2", + owner, + timeline + ); }); return () => { @@ -77,7 +85,7 @@ export function getTimelinePostUpdate$( if (connection.state === HubConnectionState.Connected) { void connection - .invoke("UnsubscribeTimelinePostChange", timelineName) + .invoke("UnsubscribeTimelinePostChangeV2", owner, timeline) .then(() => connection.stop()); } }; diff --git a/FrontEnd/src/views/timeline/Timeline.tsx b/FrontEnd/src/views/timeline/Timeline.tsx index 7fb58e0c..e8b1147f 100644 --- a/FrontEnd/src/views/timeline/Timeline.tsx +++ b/FrontEnd/src/views/timeline/Timeline.tsx @@ -62,7 +62,10 @@ const Timeline: React.FC = (props) => { React.useEffect(() => { if (timelineName != null && state === "loaded") { - const timelinePostUpdate$ = getTimelinePostUpdate$(timelineName); + const timelinePostUpdate$ = getTimelinePostUpdate$( + timelineOwner, + timelineName + ); const subscription = timelinePostUpdate$.subscribe( ({ update, state }) => { if (update) { @@ -75,7 +78,7 @@ const Timeline: React.FC = (props) => { subscription.unsubscribe(); }; } - }, [timelineName, state, onReload, onConnectionStateChanged]); + }, [timelineOwner, timelineName, state, onReload, onConnectionStateChanged]); React.useEffect(() => { if (timelineName != null) { diff --git a/FrontEnd/src/views/timeline/index.tsx b/FrontEnd/src/views/timeline/index.tsx index 3bd3ae3c..65bb90f6 100644 --- a/FrontEnd/src/views/timeline/index.tsx +++ b/FrontEnd/src/views/timeline/index.tsx @@ -4,7 +4,6 @@ import { useParams } from "react-router-dom"; import { UiLogicError } from "@/common"; import { HttpTimelineInfo } from "@/http/timeline"; -import useReverseScrollPositionRemember from "@/utilities/useReverseScrollPositionRemember"; import { generatePalette, setPalette } from "@/palette"; import Timeline from "./Timeline"; @@ -29,8 +28,6 @@ const TimelinePage: React.FC = () => { const [connectionStatus, setConnectionStatus] = React.useState(HubConnectionState.Connecting); - useReverseScrollPositionRemember(); - React.useEffect(() => { if (timeline != null && timeline.color != null) { return setPalette(generatePalette({ primary: timeline.color })); -- cgit v1.2.3