using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Timeline.Filters; using Timeline.Models.Http; using Timeline.Models.Validation; using Timeline.Services; namespace Timeline.Controllers { [ApiController] [CatchTimelineNotExistException] public class TimelineController : Controller { private readonly ILogger _logger; private readonly IUserService _userService; private readonly ITimelineService _service; public TimelineController(ILogger logger, IUserService userService, ITimelineService service) { _logger = logger; _userService = userService; _service = service; } [HttpGet("timelines")] public async Task>> TimelineList([FromQuery][Username] string? relate, [FromQuery][RegularExpression("(own)|(join)")] string? relateType, [FromQuery] string? visibility) { List? visibilityFilter = null; if (visibility != null) { visibilityFilter = new List(); var items = visibility.Split('|'); foreach (var item in items) { if (item.Equals(nameof(TimelineVisibility.Private), StringComparison.OrdinalIgnoreCase)) { if (!visibilityFilter.Contains(TimelineVisibility.Private)) visibilityFilter.Add(TimelineVisibility.Private); } else if (item.Equals(nameof(TimelineVisibility.Register), StringComparison.OrdinalIgnoreCase)) { if (!visibilityFilter.Contains(TimelineVisibility.Register)) visibilityFilter.Add(TimelineVisibility.Register); } else if (item.Equals(nameof(TimelineVisibility.Public), StringComparison.OrdinalIgnoreCase)) { if (!visibilityFilter.Contains(TimelineVisibility.Public)) visibilityFilter.Add(TimelineVisibility.Public); } else { return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_QueryVisibilityUnknown, item)); } } } TimelineUserRelationship? relationship = null; if (relate != null) { try { var relatedUserId = await _userService.GetUserIdByUsername(relate); relationship = new TimelineUserRelationship(relateType switch { "own" => TimelineUserRelationshipType.Own, "join" => TimelineUserRelationshipType.Join, _ => TimelineUserRelationshipType.Default }, relatedUserId); } catch (UserNotExistException) { return BadRequest(ErrorResponse.TimelineController.QueryRelateNotExist()); } } var result = await _service.GetTimelines(relationship, visibilityFilter); result.ForEach(t => t.FillLinks(Url)); return Ok(result); } [HttpGet("timelines/{name}")] public async Task> TimelineGet([FromRoute][TimelineName] string name) { var result = (await _service.GetTimeline(name)).FillLinks(Url); return Ok(result); } [HttpGet("timelines/{name}/posts")] public async Task>> PostListGet([FromRoute][TimelineName] string name) { if (!this.IsAdministrator() && !await _service.HasReadPermission(name, this.GetOptionalUserId())) { return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } return await _service.GetPosts(name); } [HttpPost("timelines/{name}/posts")] [Authorize] public async Task> PostPost([FromRoute][TimelineName] string name, [FromBody] TimelinePostCreateRequest body) { var id = this.GetUserId(); if (!this.IsAdministrator() && !await _service.IsMemberOf(name, id)) { return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } var res = await _service.CreatePost(name, id, body.Content, body.Time); return res; } [HttpDelete("timelines/{name}/posts/{id}")] [Authorize] public async Task PostDelete([FromRoute][TimelineName] string name, [FromRoute] long id) { try { if (!this.IsAdministrator() && !await _service.HasPostModifyPermission(name, id, this.GetUserId())) { return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } await _service.DeletePost(name, id); return Ok(CommonDeleteResponse.Delete()); } catch (TimelinePostNotExistException) { return Ok(CommonDeleteResponse.NotExist()); } } [HttpPatch("timelines/{name}")] [Authorize] public async Task> TimelinePatch([FromRoute][TimelineName] string name, [FromBody] TimelinePatchRequest body) { if (!this.IsAdministrator() && !(await _service.HasManagePermission(name, this.GetUserId()))) { return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } await _service.ChangeProperty(name, body); var timeline = (await _service.GetTimeline(name)).FillLinks(Url); return Ok(timeline); } [HttpPut("timelines/{name}/members/{member}")] [Authorize] public async Task TimelineMemberPut([FromRoute][TimelineName] string name, [FromRoute][Username] string member) { if (!this.IsAdministrator() && !(await _service.HasManagePermission(name, this.GetUserId()))) { return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } try { await _service.ChangeMember(name, new List { member }, null); return Ok(); } catch (UserNotExistException) { return BadRequest(ErrorResponse.TimelineCommon.MemberPut_NotExist()); } } [HttpDelete("timelines/{name}/members/{member}")] [Authorize] public async Task TimelineMemberDelete([FromRoute][TimelineName] string name, [FromRoute][Username] string member) { if (!this.IsAdministrator() && !(await _service.HasManagePermission(name, this.GetUserId()))) { return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } try { await _service.ChangeMember(name, null, new List { member }); return Ok(CommonDeleteResponse.Delete()); } catch (UserNotExistException) { return Ok(CommonDeleteResponse.NotExist()); } } [HttpPost("timelines")] [Authorize] public async Task> TimelineCreate([FromBody] TimelineCreateRequest body) { var userId = this.GetUserId(); try { var timelineInfo = (await _service.CreateTimeline(body.Name, userId)).FillLinks(Url); return Ok(timelineInfo); } catch (ConflictException) { return BadRequest(ErrorResponse.TimelineCommon.NameConflict()); } } } }