1
0
mirror of https://github.com/mxpv/podsync.git synced 2024-05-11 05:55:04 +00:00

Implement create feed backend API

This commit is contained in:
Maksym Pavlenko
2016-12-16 14:30:47 -08:00
parent 814a0113a9
commit c90a9bc2ad
9 changed files with 222 additions and 29 deletions

View File

@@ -1,26 +1,41 @@
using System.IO;
using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Microsoft.AspNetCore.Mvc;
using Podsync.Helpers;
using Podsync.Services;
using Podsync.Services.Builder;
using Podsync.Services.Feed;
using Podsync.Services.Links;
using Podsync.Services.Resolver;
using Podsync.Services.Storage;
namespace Podsync.Controllers
{
[Route("feed")]
public class FeedController : Controller
{
private const int DefaultPageSize = 50;
private readonly XmlSerializer _serializer = new XmlSerializer(typeof(Rss));
private readonly IRssBuilder _rssBuilder;
private readonly ILinkService _linkService;
private readonly IStorageService _storageService;
public FeedController(IRssBuilder rssBuilder)
public FeedController(IRssBuilder rssBuilder, ILinkService linkService, IStorageService storageService)
{
_rssBuilder = rssBuilder;
_linkService = linkService;
_storageService = storageService;
}
[HttpGet]
[Route("{feedId}")]
public async Task<IActionResult> Index(string feedId)
[ValidateModelState]
public async Task<IActionResult> Index([Required] string feedId)
{
var rss = await _rssBuilder.Query(feedId);
@@ -34,5 +49,24 @@ namespace Podsync.Controllers
return Content(body, "text/xml");
}
[HttpPost]
[Route("create")]
[ValidateModelState]
public Task<string> Create([FromBody] CreateFeedRequest request)
{
var linkInfo = _linkService.Parse(new Uri(request.Url));
var feed = new FeedMetadata
{
Provider = linkInfo.Provider,
LinkType = linkInfo.LinkType,
Id = linkInfo.Id,
Quality = request.Quality ?? ResolveType.VideoHigh,
PageSize = request.PageSize ?? DefaultPageSize
};
return _storageService.Save(feed);
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Podsync.Helpers
{
/// <summary>
/// Validate the model state prior to action execution.
/// See http://www.strathweb.com/2015/06/action-filters-service-filters-type-filters-asp-net-5-mvc-6/
/// </summary>
public class ValidateModelStateAttribute : ActionFilterAttribute
{
private readonly bool _validateNotNull;
public ValidateModelStateAttribute(bool validateNotNull = true)
{
_validateNotNull = validateNotNull;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid || _validateNotNull && context.ActionArguments.Any(p => p.Value == null))
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
}
}

View File

@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using Podsync.Services.Resolver;
namespace Podsync.Services
{
public class CreateFeedRequest
{
[Required]
[Url]
public string Url { get; set; }
public ResolveType? Quality { get; set; }
[Range(50, 150)]
public int? PageSize { get; set; }
}
}

View File

@@ -2,7 +2,7 @@
{
public enum ResolveType
{
VideoHigh,
VideoHigh = 0,
VideoLow,
AudioHigh,
AudioLow

View File

@@ -59,10 +59,6 @@ namespace Podsync
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

View File

@@ -0,0 +1,55 @@
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Podsync.Services;
using Podsync.Services.Resolver;
using Xunit;
namespace Podsync.Tests.Controllers
{
public class FeedControllerTests : TestServer<Startup>
{
[Fact]
public async Task ValidateCreateNullTest()
{
var response = await Client.PostAsync("/feed/create", new StringContent("", Encoding.UTF8, "application/json"));
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
[Theory]
[InlineData(null, null, null)]
[InlineData("a", null, null)]
[InlineData("http://youtube.com", null, 0)]
[InlineData("http://youtube.com", null, 25)]
[InlineData("http://youtube.com", null, 151)]
public async Task ValidateCreateTest(string url, ResolveType? quality, int? pageSize)
{
var feed = new CreateFeedRequest
{
Url = url,
Quality = quality,
PageSize = pageSize
};
var response = await Client.PostAsync("/feed/create", MakeHttpContent(feed));
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
[Fact]
public async Task CreateFeedTest()
{
var feed = new CreateFeedRequest
{
Url = "https://www.youtube.com/channel/UCKy1dAqELo0zrOtPkf0eTMw",
Quality = ResolveType.AudioLow,
};
var response = await Client.PostAsync("/feed/create", MakeHttpContent(feed));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var id = await response.Content.ReadAsStringAsync();
Assert.NotNull(id);
}
}
}

View File

@@ -0,0 +1,17 @@
using System.Threading.Tasks;
using Xunit;
namespace Podsync.Tests.Controllers
{
public class StatusControllerTests : TestServer<Startup>
{
[Fact]
public async Task StatusTest()
{
var response = await Client.GetAsync("/status");
var content = await response.Content.ReadAsStringAsync();
Assert.Contains("Path: /status", content);
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Net.Http;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Newtonsoft.Json;
namespace Podsync.Tests.Controllers
{
public abstract class TestServer<TStartup> : TestBase, IDisposable where TStartup : class
{
private readonly TestServer _server;
protected TestServer()
{
var builder = new WebHostBuilder().UseStartup<TStartup>();
_server = new TestServer(builder);
Client = _server.CreateClient();
Client.BaseAddress = new Uri("http://localhost:5000");
}
protected HttpClient Client { get; }
public void Dispose()
{
Client.Dispose();
_server.Dispose();
}
public static HttpContent MakeHttpContent(object obj)
{
var json = JsonConvert.SerializeObject(obj);
return new StringContent(json, Encoding.UTF8, "application/json");
}
}
}

View File

@@ -4,6 +4,7 @@
"dependencies": {
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"Microsoft.AspNetCore.TestHost": "1.0.1",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Microsoft.NETCore.App": {
@@ -23,5 +24,13 @@
"portable-net45+win8"
]
}
}
},
"buildOptions": {
"copyToOutput": [
"project.json"
]
},
"userSecretsId": "aspnet-Podsync-20161004104901"
}