diff options
author | crupest <crupest@outlook.com> | 2020-03-10 19:37:58 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-03-10 19:37:58 +0800 |
commit | 5eaacedda31da86116f25158bd07e5ad8954e7b2 (patch) | |
tree | b9165a233b00c4ab5be47f0ce786b64c178a9fdf /Timeline | |
parent | 08b18564bb1c477b01384cb93d62f98cfcb83f48 (diff) | |
download | timeline-5eaacedda31da86116f25158bd07e5ad8954e7b2.tar.gz timeline-5eaacedda31da86116f25158bd07e5ad8954e7b2.tar.bz2 timeline-5eaacedda31da86116f25158bd07e5ad8954e7b2.zip |
...
Diffstat (limited to 'Timeline')
-rw-r--r-- | Timeline/Controllers/TimelineController.cs | 14 | ||||
-rw-r--r-- | Timeline/Controllers/UserController.cs | 1 | ||||
-rw-r--r-- | Timeline/Entities/TimelineEntity.cs | 2 | ||||
-rw-r--r-- | Timeline/Models/Http/Timeline.cs | 24 | ||||
-rw-r--r-- | Timeline/Models/Http/UserInfo.cs | 2 | ||||
-rw-r--r-- | Timeline/Models/Timeline.cs | 17 | ||||
-rw-r--r-- | Timeline/Services/TimelineService.cs | 79 | ||||
-rw-r--r-- | Timeline/Startup.cs | 3 |
8 files changed, 97 insertions, 45 deletions
diff --git a/Timeline/Controllers/TimelineController.cs b/Timeline/Controllers/TimelineController.cs index 38fe7475..440b0d19 100644 --- a/Timeline/Controllers/TimelineController.cs +++ b/Timeline/Controllers/TimelineController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -113,6 +114,19 @@ namespace Timeline.Controllers return result;
}
+ // TODO: Make cache available.
+ [HttpGet("timelines/{name}/posts/{id}/data")]
+ public async Task<ActionResult<List<TimelinePostInfo>>> PostDataGet([FromRoute][GeneralTimelineName] string name, [FromRoute] long id)
+ {
+ if (!this.IsAdministrator() && !await _service.HasReadPermission(name, this.GetOptionalUserId()))
+ {
+ return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid());
+ }
+
+ var data = await _service.GetPostData(name, id);
+ return File(data.Data, data.Type, data.LastModified, new EntityTagHeaderValue(data.ETag));
+ }
+
[HttpPost("timelines/{name}/posts")]
[Authorize]
public async Task<ActionResult<TimelinePostInfo>> PostPost([FromRoute][GeneralTimelineName] string name, [FromBody] TimelinePostCreateRequest body)
diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index a3e8d816..0bc8bcda 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading.Tasks;
using Timeline.Auth;
using Timeline.Helpers;
+using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Models.Validation;
using Timeline.Services;
diff --git a/Timeline/Entities/TimelineEntity.cs b/Timeline/Entities/TimelineEntity.cs index 56b36d4e..3149d4c2 100644 --- a/Timeline/Entities/TimelineEntity.cs +++ b/Timeline/Entities/TimelineEntity.cs @@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
-using Timeline.Models.Http;
+using Timeline.Models;
namespace Timeline.Entities
{
diff --git a/Timeline/Models/Http/Timeline.cs b/Timeline/Models/Http/Timeline.cs index 55c3a3bf..9e2aefd0 100644 --- a/Timeline/Models/Http/Timeline.cs +++ b/Timeline/Models/Http/Timeline.cs @@ -72,25 +72,27 @@ namespace Timeline.Models.Http }
}
- public class TimelinePostConverter : ITypeConverter<ITimelinePostContent, TimelinePostContentInfo>
+ public class TimelinePostContentResolver : IValueResolver<TimelinePost, TimelinePostInfo, TimelinePostContentInfo>
{
private readonly IActionContextAccessor _actionContextAccessor;
private readonly IUrlHelperFactory _urlHelperFactory;
- public TimelinePostConverter(IActionContextAccessor actionContextAccessor, IUrlHelperFactory urlHelperFactory)
+ public TimelinePostContentResolver(IActionContextAccessor actionContextAccessor, IUrlHelperFactory urlHelperFactory)
{
_actionContextAccessor = actionContextAccessor;
_urlHelperFactory = urlHelperFactory;
}
- public TimelinePostContentInfo Convert(ITimelinePostContent source, TimelinePostContentInfo destination, ResolutionContext context)
+ public TimelinePostContentInfo Resolve(TimelinePost source, TimelinePostInfo destination, TimelinePostContentInfo destMember, ResolutionContext context)
{
if (_actionContextAccessor.ActionContext == null)
throw new InvalidOperationException("No action context, can't fill urls.");
var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);
- if (source is TextTimelinePostContent textContent)
+ var sourceContent = source.Content;
+
+ if (sourceContent is TextTimelinePostContent textContent)
{
return new TimelinePostContentInfo
{
@@ -98,14 +100,21 @@ namespace Timeline.Models.Http Text = textContent.Text
};
}
- else if (source is ImageTimelinePostContent imageContent)
+ else if (sourceContent is ImageTimelinePostContent imageContent)
{
return new TimelinePostContentInfo
{
Type = TimelinePostContentTypes.Image,
- Url = urlHelper.ActionLink(action: "PostDataGet", nameof(TimelineController)[0..^nameof(Controller).Length], new { source.Name })
+ Url = urlHelper.ActionLink(
+ action: nameof(TimelineController.PostDataGet),
+ controller: nameof(TimelineController)[0..^nameof(Controller).Length],
+ values: new { Name = source.TimelineName, Id = source.Id })
};
}
+ else
+ {
+ throw new InvalidOperationException("Unknown content type.");
+ }
}
}
@@ -114,8 +123,7 @@ namespace Timeline.Models.Http public TimelineInfoAutoMapperProfile()
{
CreateMap<Timeline, TimelineInfo>().ForMember(u => u._links, opt => opt.MapFrom<TimelineInfoLinksValueResolver>());
- CreateMap<TimelinePost, TimelinePostInfo>();
- CreateMap<ITimelinePostContent, TimelinePostContentInfo>().ConvertUsing<TimelinePostConverter>();
+ CreateMap<TimelinePost, TimelinePostInfo>().ForMember(p => p.Content, opt => opt.MapFrom<TimelinePostContentResolver>());
CreateMap<TimelinePatchRequest, TimelineChangePropertyRequest>();
}
}
diff --git a/Timeline/Models/Http/UserInfo.cs b/Timeline/Models/Http/UserInfo.cs index 4f887549..b4bf14c1 100644 --- a/Timeline/Models/Http/UserInfo.cs +++ b/Timeline/Models/Http/UserInfo.cs @@ -45,7 +45,7 @@ namespace Timeline.Models.Http {
Self = urlHelper.ActionLink(nameof(UserController.Get), nameof(UserController)[0..^nameof(Controller).Length], new { destination.Username }),
Avatar = urlHelper.ActionLink(nameof(UserAvatarController.Get), nameof(UserAvatarController)[0..^nameof(Controller).Length], new { destination.Username }),
- Timeline = urlHelper.ActionLink(nameof(PersonalTimelineController.TimelineGet), nameof(PersonalTimelineController)[0..^nameof(Controller).Length], new { destination.Username })
+ Timeline = urlHelper.ActionLink(nameof(TimelineController.TimelineGet), nameof(TimelineController)[0..^nameof(Controller).Length], new { Name = "@" + destination.Username })
};
return result;
}
diff --git a/Timeline/Models/Timeline.cs b/Timeline/Models/Timeline.cs index 6d4c924d..803a5c5c 100644 --- a/Timeline/Models/Timeline.cs +++ b/Timeline/Models/Timeline.cs @@ -48,11 +48,22 @@ namespace Timeline.Models public class TimelinePost
{
+ public TimelinePost(long id, ITimelinePostContent content, DateTime time, User author, DateTime lastUpdated, string timelineName)
+ {
+ Id = id;
+ Content = content;
+ Time = time;
+ Author = author;
+ LastUpdated = lastUpdated;
+ TimelineName = timelineName;
+ }
+
public long Id { get; set; }
- public ITimelinePostContent Content { get; set; } = default!;
+ public ITimelinePostContent Content { get; set; }
public DateTime Time { get; set; }
- public User Author { get; set; } = default!;
- public DateTime LastUpdated { get; set; } = default!;
+ public User Author { get; set; }
+ public DateTime LastUpdated { get; set; }
+ public string TimelineName { get; set; }
}
#pragma warning disable CA1724 // Type names should not match namespaces
diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs index 1bccb855..3a5825ae 100644 --- a/Timeline/Services/TimelineService.cs +++ b/Timeline/Services/TimelineService.cs @@ -32,12 +32,14 @@ namespace Timeline.Services public long UserId { get; set; }
}
- public class DataWithType
+ public class PostData
{
#pragma warning disable CA1819 // Properties should not return arrays
public byte[] Data { get; set; } = default!;
#pragma warning restore CA1819 // Properties should not return arrays
public string Type { get; set; } = default!;
+ public string ETag { get; set; } = default!;
+ public DateTime LastModified { get; set; } = default!;
}
/// <summary>
@@ -103,7 +105,7 @@ namespace Timeline.Services /// <remarks>
/// Use this method to retrieve the image of image post.
/// </remarks>
- Task<DataWithType> GetPostData(string name, long postId);
+ Task<PostData> GetPostData(string name, long postId);
/// <summary>
/// Create a new text post in timeline.
@@ -334,6 +336,8 @@ namespace Timeline.Services /// </remarks>
protected abstract Task<long> FindTimelineId(string name);
+ protected abstract string GenerateName(string name);
+
public async Task<Models.Timeline> GetTimeline(string name)
{
if (name == null)
@@ -355,7 +359,7 @@ namespace Timeline.Services return new Models.Timeline
{
- Name = timelineEntity.Name ?? ("@" + owner.Username),
+ Name = GenerateName(name),
Description = timelineEntity.Description ?? "",
Owner = owner,
Visibility = timelineEntity.Visibility,
@@ -387,19 +391,19 @@ namespace Timeline.Services _ => throw new DatabaseCorruptedException(string.Format(CultureInfo.InvariantCulture, ExceptionDatabaseUnknownContentType, type))
};
- posts.Add(new TimelinePost
- {
- Id = entity.LocalId,
- Content = content,
- Author = author,
- Time = entity.Time,
- LastUpdated = entity.LastUpdated
- });
+ posts.Add(new TimelinePost(
+ id: entity.LocalId,
+ content: content,
+ time: entity.Time,
+ author: author,
+ lastUpdated: entity.LastUpdated,
+ timelineName: GenerateName(name)
+ ));
}
}
return posts;
}
- public async Task<DataWithType> GetPostData(string name, long postId)
+ public async Task<PostData> GetPostData(string name, long postId)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
@@ -437,10 +441,12 @@ namespace Timeline.Services await Database.SaveChangesAsync();
}
- return new DataWithType
+ return new PostData
{
Data = data,
- Type = postEntity.ExtraContent
+ Type = postEntity.ExtraContent,
+ ETag = tag,
+ LastModified = postEntity.LastUpdated
};
}
@@ -474,14 +480,15 @@ namespace Timeline.Services Database.TimelinePosts.Add(postEntity);
await Database.SaveChangesAsync();
- return new TimelinePost
- {
- Id = postEntity.LocalId,
- Content = new TextTimelinePostContent(text),
- Author = author,
- Time = finalTime,
- LastUpdated = currentTime
- };
+
+ return new TimelinePost(
+ id: postEntity.LocalId,
+ content: new TextTimelinePostContent(text),
+ time: finalTime,
+ author: author,
+ lastUpdated: currentTime,
+ timelineName: GenerateName(name)
+ );
}
public async Task<TimelinePost> CreateImagePost(string name, long authorId, byte[] data, DateTime? time)
@@ -521,14 +528,14 @@ namespace Timeline.Services Database.TimelinePosts.Add(postEntity);
await Database.SaveChangesAsync();
- return new TimelinePost
- {
- Id = postEntity.LocalId,
- Content = new ImageTimelinePostContent(tag),
- Author = author,
- Time = finalTime,
- LastUpdated = currentTime
- };
+ return new TimelinePost(
+ id: postEntity.LocalId,
+ content: new ImageTimelinePostContent(tag),
+ time: finalTime,
+ author: author,
+ lastUpdated: currentTime,
+ timelineName: GenerateName(name)
+ );
}
public async Task DeletePost(string name, long id)
@@ -767,6 +774,11 @@ namespace Timeline.Services return timelineEntity.Id;
}
}
+
+ protected override string GenerateName(string name)
+ {
+ return name;
+ }
}
public class PersonalTimelineService : BaseTimelineManager, IPersonalTimelineService
@@ -818,6 +830,11 @@ namespace Timeline.Services return newTimelineEntity.Id;
}
}
+
+ protected override string GenerateName(string name)
+ {
+ return "@" + name;
+ }
}
public class TimelineService : ITimelineService
@@ -996,7 +1013,7 @@ namespace Timeline.Services return s.GetPosts(realName);
}
- public Task<DataWithType> GetPostData(string name, long postId)
+ public Task<PostData> GetPostData(string name, long postId)
{
var s = BranchName(name, out var realName);
return s.GetPostData(realName, postId);
diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 85822a14..d2fd22bd 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -101,7 +101,8 @@ namespace Timeline services.AddUserAvatarService();
- services.AddScoped<ITimelineService, TimelineManager>();
+ services.AddScoped<ITimelineService, TimelineService>();
+ services.AddScoped<IOrdinaryTimelineService, OrdinaryTimelineService>();
services.AddScoped<IPersonalTimelineService, PersonalTimelineService>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
|