From 5658347ebafdae2bb82e96f57299e40ddec58f28 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 12 Jul 2020 15:54:09 +0800 Subject: Add api in service. --- Timeline/Services/TimelineService.cs | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'Timeline') diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs index a0d72ad3..eafb0088 100644 --- a/Timeline/Services/TimelineService.cs +++ b/Timeline/Services/TimelineService.cs @@ -66,6 +66,32 @@ namespace Timeline.Services /// public interface ITimelineService { + /// + /// Get the timeline last modified time (not include name change). + /// + /// The name of the timeline. + /// The timeline info. + /// Thrown when is null. + /// Throw when is of bad format. + /// + /// Thrown when timeline with name does not exist. + /// If it is a personal timeline, then inner exception is . + /// + Task GetTimelineLastModifiedTime(string timelineName); + + /// + /// Get the timeline unique id. + /// + /// The name of the timeline. + /// The timeline info. + /// Thrown when is null. + /// Throw when is of bad format. + /// + /// Thrown when timeline with name does not exist. + /// If it is a personal timeline, then inner exception is . + /// + Task GetTimelineUniqueId(string timelineName); + /// /// Get the timeline info. /// @@ -497,6 +523,30 @@ namespace Timeline.Services } } + public async Task GetTimelineLastModifiedTime(string timelineName) + { + if (timelineName == null) + throw new ArgumentNullException(nameof(timelineName)); + + var timelineId = await FindTimelineId(timelineName); + + var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.LastModified }).SingleAsync(); + + return timelineEntity.LastModified; + } + + public async Task GetTimelineUniqueId(string timelineName) + { + if (timelineName == null) + throw new ArgumentNullException(nameof(timelineName)); + + var timelineId = await FindTimelineId(timelineName); + + var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.UniqueId }).SingleAsync(); + + return timelineEntity.UniqueId; + } + public async Task GetTimeline(string timelineName) { if (timelineName == null) -- cgit v1.2.3 From ad187b72edc974e1258a058785d879ba8d8afadf Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 12 Jul 2020 17:12:47 +0800 Subject: Add http api and integrated tests. --- Timeline.Tests/IntegratedTests/TimelineTest.cs | 75 ++++++++++++++++++++++++++ Timeline/Controllers/TimelineController.cs | 47 ++++++++++++++-- 2 files changed, 118 insertions(+), 4 deletions(-) (limited to 'Timeline') diff --git a/Timeline.Tests/IntegratedTests/TimelineTest.cs b/Timeline.Tests/IntegratedTests/TimelineTest.cs index ba335bd6..49672f29 100644 --- a/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -1332,5 +1332,80 @@ namespace Timeline.Tests.IntegratedTests posts.Select(p => p.Content == null).Should().Equal(false, true, false); } } + + [Theory] + [MemberData(nameof(TimelineUrlGeneratorData))] + public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineUrlGenerator urlGenerator) + { + using var client = await CreateClientAsUser(); + + DateTime lastModifiedTime; + TimelineInfo timeline; + string uniqueId; + + { + var res = await client.GetAsync(urlGenerator(1)); + var body = res.Should().HaveStatusCode(200) + .And.HaveJsonBody().Which; + timeline = body; + lastModifiedTime = body.LastModified; + uniqueId = body.UniqueId; + } + + { + using var req = new HttpRequestMessage + { + RequestUri = new Uri(client.BaseAddress, urlGenerator(1)), + Method = HttpMethod.Get, + }; + req.Headers.IfModifiedSince = lastModifiedTime.AddSeconds(1); + var res = await client.SendAsync(req); + res.Should().HaveStatusCode(304); + } + + { + using var req = new HttpRequestMessage + { + RequestUri = new Uri(client.BaseAddress, urlGenerator(1)), + Method = HttpMethod.Get, + }; + req.Headers.IfModifiedSince = lastModifiedTime.AddSeconds(-1); + var res = await client.SendAsync(req); + res.Should().HaveStatusCode(200) + .And.HaveJsonBody() + .Which.Should().BeEquivalentTo(timeline); + } + + { + var res = await client.GetAsync(urlGenerator(1, null, + new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) } })); + res.Should().HaveStatusCode(304); + } + + { + var res = await client.GetAsync(urlGenerator(1, null, + new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(-1).ToString("s", CultureInfo.InvariantCulture) } })); + res.Should().HaveStatusCode(200) + .And.HaveJsonBody() + .Which.Should().BeEquivalentTo(timeline); + } + + { + var res = await client.GetAsync(urlGenerator(1, null, + new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, + {"checkUniqueId", uniqueId } })); + res.Should().HaveStatusCode(304); + } + + { + var testUniqueId = (uniqueId[0] == 'a' ? "b" : "a") + uniqueId[1..]; + var res = await client.GetAsync(urlGenerator(1, null, + new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, + {"checkUniqueId", testUniqueId } })); + res.Should().HaveStatusCode(200) + .And.HaveJsonBody() + .Which.Should().BeEquivalentTo(timeline); + } + } } } diff --git a/Timeline/Controllers/TimelineController.cs b/Timeline/Controllers/TimelineController.cs index 2330698f..72404ea3 100644 --- a/Timeline/Controllers/TimelineController.cs +++ b/Timeline/Controllers/TimelineController.cs @@ -94,11 +94,50 @@ namespace Timeline.Controllers } [HttpGet("timelines/{name}")] - public async Task> TimelineGet([FromRoute][GeneralTimelineName] string name) + public async Task> TimelineGet([FromRoute][GeneralTimelineName] string name, [FromQuery] string? checkUniqueId, [FromQuery(Name = "ifModifiedSince")] DateTime? queryIfModifiedSince, [FromHeader(Name = "If-Modified-Since")] DateTime? headerIfModifiedSince) { - var timeline = await _service.GetTimeline(name); - var result = _mapper.Map(timeline); - return result; + DateTime? ifModifiedSince = null; + if (queryIfModifiedSince.HasValue) + { + ifModifiedSince = queryIfModifiedSince.Value; + } + else if (headerIfModifiedSince != null) + { + ifModifiedSince = headerIfModifiedSince.Value; + } + + bool returnNotModified = false; + + if (ifModifiedSince.HasValue) + { + var lastModified = await _service.GetTimelineLastModifiedTime(name); + if (lastModified < ifModifiedSince.Value) + { + if (checkUniqueId != null) + { + var uniqueId = await _service.GetTimelineUniqueId(name); + if (uniqueId == checkUniqueId) + { + returnNotModified = true; + } + } + else + { + returnNotModified = true; + } + } + } + + if (returnNotModified) + { + return StatusCode(StatusCodes.Status304NotModified); + } + else + { + var timeline = await _service.GetTimeline(name); + var result = _mapper.Map(timeline); + return result; + } } [HttpGet("timelines/{name}/posts")] -- cgit v1.2.3