using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Timeline.Entities;
using Timeline.Filters;
using Timeline.Helpers;
using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Models.Mapper;
using Timeline.Models.Validation;
using Timeline.Services;
using Timeline.Services.Exceptions;
namespace Timeline.Controllers
{
///
/// Operations about timeline.
///
[ApiController]
[Route("timelines/{timeline}/posts")]
[CatchTimelineNotExistException]
[ProducesErrorResponseType(typeof(CommonResponse))]
public class TimelinePostController : Controller
{
private readonly ITimelineService _timelineService;
private readonly ITimelinePostService _postService;
private readonly TimelineMapper _timelineMapper;
///
///
///
public TimelinePostController(ITimelineService timelineService, ITimelinePostService timelinePostService, TimelineMapper timelineMapper)
{
_timelineService = timelineService;
_postService = timelinePostService;
_timelineMapper = timelineMapper;
}
private bool UserHasAllTimelineManagementPermission => this.UserHasPermission(UserPermission.AllTimelineManagement);
///
/// Get posts of a timeline.
///
/// The name of the timeline.
/// If set, only posts modified since the time will return.
/// If set to true, deleted post will also return.
/// The post list.
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task>> PostList([FromRoute][GeneralTimelineName] string timeline, [FromQuery] DateTime? modifiedSince, [FromQuery] bool? includeDeleted)
{
var timelineId = await _timelineService.GetTimelineIdByName(timeline);
if (!UserHasAllTimelineManagementPermission && !await _timelineService.HasReadPermission(timelineId, this.GetOptionalUserId()))
{
return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid());
}
var posts = await _postService.GetPosts(timelineId, modifiedSince, includeDeleted ?? false);
var result = await _timelineMapper.MapToHttp(posts, timeline, Url);
return result;
}
///
/// Get the data of a post. Usually a image post.
///
/// Timeline name.
/// The id of the post.
/// If-None-Match header.
/// The data.
[HttpGet("{post}/data")]
[Produces("image/png", "image/jpeg", "image/gif", "image/webp", "application/json", "text/json")]
[ProducesResponseType(typeof(byte[]), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status304NotModified)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task PostDataGet([FromRoute][GeneralTimelineName] string timeline, [FromRoute] long post, [FromHeader(Name = "If-None-Match")] string? ifNoneMatch)
{
_ = ifNoneMatch;
var timelineId = await _timelineService.GetTimelineIdByName(timeline);
if (!UserHasAllTimelineManagementPermission && !await _timelineService.HasReadPermission(timelineId, this.GetOptionalUserId()))
{
return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid());
}
try
{
return await DataCacheHelper.GenerateActionResult(this,
() => _postService.GetPostDataETag(timelineId, post),
async () => await _postService.GetPostData(timelineId, post));
}
catch (TimelinePostNotExistException)
{
return NotFound(ErrorResponse.TimelineController.PostNotExist());
}
catch (TimelinePostNoDataException)
{
return BadRequest(ErrorResponse.TimelineController.PostNoData());
}
}
///
/// Create a new post.
///
/// Timeline name.
///
/// Info of new post.
[HttpPost]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task> PostPost([FromRoute][GeneralTimelineName] string timeline, [FromBody] HttpTimelinePostCreateRequest body)
{
var timelineId = await _timelineService.GetTimelineIdByName(timeline);
var userId = this.GetUserId();
if (!UserHasAllTimelineManagementPermission && !await _timelineService.IsMemberOf(timelineId, userId))
{
return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid());
}
var content = body.Content;
TimelinePostEntity post;
TimelinePostCommonProperties properties = new TimelinePostCommonProperties { Color = body.Color, Time = body.Time };
if (content.Type == TimelinePostContentTypes.Text)
{
var text = content.Text;
if (text == null)
{
return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_TextContentTextRequired));
}
post = await _postService.CreateTextPost(timelineId, userId, text, properties);
}
else if (content.Type == TimelinePostContentTypes.Image)
{
var base64Data = content.Data;
if (base64Data == null)
{
return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_ImageContentDataRequired));
}
byte[] data;
try
{
data = Convert.FromBase64String(base64Data);
}
catch (FormatException)
{
return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_ImageContentDataNotBase64));
}
try
{
post = await _postService.CreateImagePost(timelineId, userId, data, properties);
}
catch (ImageException)
{
return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_ImageContentDataNotImage));
}
}
else
{
return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_ContentUnknownType));
}
var result = await _timelineMapper.MapToHttp(post, timeline, Url);
return result;
}
///
/// Delete a post.
///
/// Timeline name.
/// Post id.
/// Info of deletion.
[HttpDelete("{post}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task PostDelete([FromRoute][GeneralTimelineName] string timeline, [FromRoute] long post)
{
var timelineId = await _timelineService.GetTimelineIdByName(timeline);
try
{
if (!UserHasAllTimelineManagementPermission && !await _postService.HasPostModifyPermission(timelineId, post, this.GetUserId(), true))
{
return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid());
}
await _postService.DeletePost(timelineId, post);
return Ok();
}
catch (TimelinePostNotExistException)
{
return BadRequest(ErrorResponse.TimelineController.PostNotExist());
}
}
}
}