diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index 213245732..efbf3dade 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Ombi/Controllers/External/EmbyController.cs b/src/Ombi/Controllers/External/EmbyController.cs index 2bca2337f..ad5869752 100644 --- a/src/Ombi/Controllers/External/EmbyController.cs +++ b/src/Ombi/Controllers/External/EmbyController.cs @@ -21,6 +21,11 @@ namespace Ombi.Controllers.External private IEmbyApi EmbyApi { get; } private ISettingsService EmbySettings { get; } + /// + /// Signs into the Emby Api + /// + /// The request. + /// [HttpPost] [AllowAnonymous] public async Task SignIn([FromBody] EmbySettings request) diff --git a/src/Ombi/Controllers/External/PlexController.cs b/src/Ombi/Controllers/External/PlexController.cs index f81b83fa2..744a85550 100644 --- a/src/Ombi/Controllers/External/PlexController.cs +++ b/src/Ombi/Controllers/External/PlexController.cs @@ -25,6 +25,11 @@ namespace Ombi.Controllers.External private IPlexApi PlexApi { get; } private ISettingsService PlexSettings { get; } + /// + /// Signs into the Plex API. + /// + /// The request. + /// [HttpPost] [AllowAnonymous] public async Task SignIn([FromBody] UserRequest request) @@ -75,6 +80,11 @@ PlexAuthToken = result.user.authentication_token, return result; } + /// + /// Gets the plex libraries. + /// + /// The settings. + /// [HttpPost("Libraries")] public async Task GetPlexLibraries([FromBody] PlexServers settings) { @@ -83,6 +93,11 @@ PlexAuthToken = result.user.authentication_token, return libs; } + /// + /// Gets the plex servers. + /// + /// The u. + /// [HttpPost("servers")] public async Task GetServers([FromBody] UserRequest u) { diff --git a/src/Ombi/Controllers/External/RadarrController.cs b/src/Ombi/Controllers/External/RadarrController.cs index 94666e9ed..ea86cca66 100644 --- a/src/Ombi/Controllers/External/RadarrController.cs +++ b/src/Ombi/Controllers/External/RadarrController.cs @@ -21,12 +21,22 @@ namespace Ombi.Controllers.External private IRadarrApi RadarrApi { get; } private ISettingsService RadarrSettings { get; } + /// + /// Gets the Radarr profiles. + /// + /// The settings. + /// [HttpPost("Profiles")] public async Task> GetProfiles([FromBody] RadarrSettings settings) { return await RadarrApi.GetProfiles(settings.ApiKey, settings.FullUri); } + /// + /// Gets the Radar root folders. + /// + /// The settings. + /// [HttpPost("RootFolders")] public async Task> GetRootFolders([FromBody] RadarrSettings settings) { diff --git a/src/Ombi/Controllers/External/SonarrController.cs b/src/Ombi/Controllers/External/SonarrController.cs index 7a8c271c3..ac4bdfab0 100644 --- a/src/Ombi/Controllers/External/SonarrController.cs +++ b/src/Ombi/Controllers/External/SonarrController.cs @@ -22,12 +22,22 @@ namespace Ombi.Controllers.External private ISonarrApi SonarrApi { get; } private ISettingsService SonarrSettings { get; } + /// + /// Gets the Sonarr profiles. + /// + /// The settings. + /// [HttpPost("Profiles")] public async Task> GetProfiles([FromBody] SonarrSettings settings) { return await SonarrApi.GetProfiles(settings.ApiKey, settings.FullUri); } + /// + /// Gets the Sonarr root folders. + /// + /// The settings. + /// [HttpPost("RootFolders")] public async Task> GetRootFolders([FromBody] SonarrSettings settings) { diff --git a/src/Ombi/Controllers/HomeController.cs b/src/Ombi/Controllers/HomeController.cs index 07a23e7f5..fdae5b6ff 100644 --- a/src/Ombi/Controllers/HomeController.cs +++ b/src/Ombi/Controllers/HomeController.cs @@ -2,8 +2,13 @@ namespace Ombi.Controllers { + [ApiExplorerSettings(IgnoreApi = true)] public class HomeController : Controller { + /// + /// Indexes this instance. + /// + /// public IActionResult Index() { return View(); diff --git a/src/Ombi/Controllers/IdentityController.cs b/src/Ombi/Controllers/IdentityController.cs index 2d3a2e640..cec0b1515 100644 --- a/src/Ombi/Controllers/IdentityController.cs +++ b/src/Ombi/Controllers/IdentityController.cs @@ -16,6 +16,10 @@ using Ombi.Models; namespace Ombi.Controllers { + /// + /// The Identity Controller, the API for everything Identity/User related + /// + /// [PowerUser] public class IdentityController : BaseV1ApiController { @@ -28,6 +32,10 @@ namespace Ombi.Controllers private IUserIdentityManager IdentityManager { get; } private IMapper Mapper { get; } + /// + /// Gets the current user. + /// + /// Information about the current user [HttpGet] public async Task GetUser() { @@ -40,11 +48,12 @@ namespace Ombi.Controllers /// This should never be called after this. /// The reason why we return false if users exists is that this method doesn't have any /// authorization and could be called from anywhere. - /// We have [AllowAnonymous] since when going through the wizard we do not have a JWT Token yet /// + /// We have [AllowAnonymous] since when going through the wizard we do not have a JWT Token yet /// /// [HttpPost("Wizard")] + [ApiExplorerSettings(IgnoreApi = true)] [AllowAnonymous] public async Task CreateWizardUser([FromBody] UserAuthModel user) { @@ -66,6 +75,10 @@ namespace Ombi.Controllers return true; } + /// + /// Gets all users. + /// + /// Information about all users [HttpGet("Users")] public async Task> GetAllUsers() { @@ -95,6 +108,11 @@ namespace Ombi.Controllers return users; } + /// + /// Creates the user. + /// + /// The user. + /// [HttpPost] public async Task CreateUser([FromBody] UserViewModel user) { @@ -102,7 +120,12 @@ namespace Ombi.Controllers var userResult = await IdentityManager.CreateUser(Mapper.Map(user)); return Mapper.Map(userResult); } - + + /// + /// Updates the user. + /// + /// The user. + /// [HttpPut] public async Task UpdateUser([FromBody] UserViewModel user) { @@ -110,6 +133,11 @@ namespace Ombi.Controllers return Mapper.Map(userResult); } + /// + /// Deletes the user. + /// + /// The user. + /// [HttpDelete] public async Task DeleteUser([FromBody] UserViewModel user) { @@ -117,6 +145,10 @@ namespace Ombi.Controllers return Ok(); } + /// + /// Gets all available claims in the system. + /// + /// [HttpGet("claims")] public IEnumerable GetAllClaims() { diff --git a/src/Ombi/Controllers/RequestController.cs b/src/Ombi/Controllers/RequestController.cs index 14eb06b90..a16c1d074 100644 --- a/src/Ombi/Controllers/RequestController.cs +++ b/src/Ombi/Controllers/RequestController.cs @@ -24,78 +24,140 @@ namespace Ombi.Controllers private IMovieRequestEngine MovieRequestEngine { get; } private ITvRequestEngine TvRequestEngine { get; } + /// + /// Gets movie requests. + /// + /// The count of items you want to return. + /// The position. [HttpGet("movie/{count:int}/{position:int}")] public async Task> GetRequests(int count, int position) { return await MovieRequestEngine.GetRequests(count, position); } + /// + /// Gets all movie requests. + /// [HttpGet("movie")] public async Task> GetRequests() { return await MovieRequestEngine.GetRequests(); } + /// + /// Requests a movie. + /// + /// The movie. + /// [HttpPost("movie")] public async Task RequestMovie([FromBody] SearchMovieViewModel movie) { return await MovieRequestEngine.RequestMovie(movie); } + /// + /// Searches for a specific movie request + /// + /// The search term. + /// [HttpGet("movie/search/{searchTerm}")] public async Task> Search(string searchTerm) { return await MovieRequestEngine.SearchMovieRequest(searchTerm); } + /// + /// Deletes the specified movie request. + /// + /// The request identifier. + /// [HttpDelete("movie/{requestId:int}")] public async Task DeleteRequest(int requestId) { await MovieRequestEngine.RemoveMovieRequest(requestId); } + /// + /// Updates the specified movie request. + /// + /// The model. + /// [HttpPut("movie")] public async Task UpdateRequest([FromBody] MovieRequestModel model) { return await MovieRequestEngine.UpdateMovieRequest(model); } + /// + /// Gets the tv requests. + /// + /// The count of items you want to return. + /// The position. + /// [HttpGet("tv/{count:int}/{position:int}")] public async Task> GetTvRequests(int count, int position) { return await TvRequestEngine.GetRequests(count, position); } + /// + /// Gets the tv requests. + /// + /// [HttpGet("tv")] public async Task> GetTvRequests() { return await TvRequestEngine.GetRequests(); } + /// + /// Requests a tv show/episode/season. + /// + /// The tv. + /// [HttpPost("tv")] public async Task RequestTv([FromBody] SearchTvShowViewModel tv) { return await TvRequestEngine.RequestTvShow(tv); } + /// + /// Searches for a specific tv request + /// + /// The search term. + /// [HttpGet("tv/search/{searchTerm}")] public async Task> SearchTv(string searchTerm) { return await TvRequestEngine.SearchTvRequest(searchTerm); } + /// + /// Deletes the a specific tv request + /// + /// The request identifier. + /// [HttpDelete("tv/{requestId:int}")] public async Task DeleteTvRequest(int requestId) { await TvRequestEngine.RemoveTvRequest(requestId); } + /// + /// Updates the a specific tv request + /// + /// The model. + /// [HttpPut("tv")] public async Task UpdateRequest([FromBody] TvRequestModel model) { return await TvRequestEngine.UpdateTvRequest(model); } + /// + /// Gets the count of total requests + /// + /// [HttpGet("count")] [AllowAnonymous] public RequestCountModel GetCountOfRequests() @@ -104,13 +166,23 @@ namespace Ombi.Controllers return TvRequestEngine.RequestCount(); } + /// + /// Gets the specific grid model for the requests (for modelling the UI). + /// + /// [HttpGet("tv/grid")] + [ApiExplorerSettings(IgnoreApi = true)] public async Task> GetTvRequestsGrid() { return await GetGrid(TvRequestEngine); } + /// + /// Gets the specific grid model for the requests (for modelling the UI). + /// + /// [HttpGet("movie/grid")] + [ApiExplorerSettings(IgnoreApi = true)] public async Task> GetMovieRequestsGrid() { return await GetGrid(MovieRequestEngine); diff --git a/src/Ombi/Controllers/SearchController.cs b/src/Ombi/Controllers/SearchController.cs index 3c986521b..b53257603 100644 --- a/src/Ombi/Controllers/SearchController.cs +++ b/src/Ombi/Controllers/SearchController.cs @@ -26,6 +26,12 @@ namespace Ombi.Controllers private IMovieEngine MovieEngine { get; } private ITvSearchEngine TvEngine { get; } + /// + /// Searches for a movie. + /// + /// We use TheMovieDb as the Movie Provider + /// The search term. + /// [HttpGet("movie/{searchTerm}")] public async Task> SearchMovie(string searchTerm) { @@ -33,60 +39,118 @@ namespace Ombi.Controllers return await MovieEngine.Search(searchTerm); } + /// + /// Gets extra information on the movie e.g. IMDBId + /// + /// We use TheMovieDb as the Movie Provider + /// The model. + /// [HttpPost("movie/extrainfo")] public async Task> GetImdbInfo([FromBody]IEnumerable model) { return await MovieEngine.LookupImdbInformation(model); } + /// + /// Returns Popular Movies + /// + /// We use TheMovieDb as the Movie Provider + /// [HttpGet("movie/popular")] public async Task> Popular() { return await MovieEngine.PopularMovies(); } + /// + /// Retuns Now Playing Movies + /// + /// We use TheMovieDb as the Movie Provider + /// [HttpGet("movie/nowplaying")] public async Task> NowPlayingMovies() { return await MovieEngine.NowPlayingMovies(); } + /// + /// Returns top rated movies. + /// + /// + /// We use TheMovieDb as the Movie Provider [HttpGet("movie/toprated")] public async Task> TopRatedMovies() { return await MovieEngine.TopRatedMovies(); } + /// + /// Returns Upcoming movies. + /// + /// We use TheMovieDb as the Movie Provider + /// [HttpGet("movie/upcoming")] public async Task> UpcomingMovies() { return await MovieEngine.UpcomingMovies(); } + /// + /// Searches for a Tv Show. + /// + /// The search term. + /// We use TvMaze as the Provider + /// [HttpGet("tv/{searchTerm}")] public async Task> SearchTv(string searchTerm) { return await TvEngine.Search(searchTerm); } + /// + /// Gets extra show information. + /// + /// The TVDB identifier. + /// We use TvMaze as the Provider + /// [HttpGet("tv/info/{tvdbId}")] public async Task GetShowInfo(int tvdbId) { return await TvEngine.GetShowInformation(tvdbId); } + /// + /// Returns Popular Tv Shows + /// + /// We use Trakt.tv as the Provider + /// [HttpGet("tv/popular")] public async Task> PopularTv() { return await TvEngine.Popular(); } + /// + /// Returns most Anticiplateds tv shows. + /// + /// We use Trakt.tv as the Provider + /// [HttpGet("tv/anticiplated")] public async Task> AnticiplatedTv() { return await TvEngine.Anticipated(); } + /// + /// Returns Most watched shows. + /// + /// We use Trakt.tv as the Provider + /// [HttpGet("tv/mostwatched")] public async Task> MostWatched() { return await TvEngine.MostWatches(); } + /// + /// Returns trending shows + /// + /// We use Trakt.tv as the Provider + /// [HttpGet("tv/trending")] public async Task> Trending() { diff --git a/src/Ombi/Controllers/SettingsController.cs b/src/Ombi/Controllers/SettingsController.cs index 371a6c9ea..ad9fb51db 100644 --- a/src/Ombi/Controllers/SettingsController.cs +++ b/src/Ombi/Controllers/SettingsController.cs @@ -20,42 +20,73 @@ namespace Ombi.Controllers private ISettingsResolver SettingsResolver { get; } + /// + /// Gets the Ombi settings. + /// + /// [HttpGet("ombi")] public async Task OmbiSettings() { return await Get(); } + /// + /// Save the Ombi settings. + /// + /// The ombi. + /// [HttpPost("ombi")] public async Task OmbiSettings([FromBody]OmbiSettings ombi) { return await Save(ombi); } + /// + /// Gets the Plex Settings. + /// + /// [HttpGet("plex")] public async Task PlexSettings() { return await Get(); } + /// + /// Save the Plex settings. + /// + /// The plex. + /// [HttpPost("plex")] public async Task PlexSettings([FromBody]PlexSettings plex) { return await Save(plex); } + /// + /// Gets the Emby Settings. + /// + /// [HttpGet("emby")] public async Task EmbySettings() { return await Get(); } + /// + /// Save the Emby settings. + /// + /// The emby. + /// [HttpPost("emby")] public async Task EmbySettings([FromBody]EmbySettings emby) { return await Save(emby); } + /// + /// Gets the Landing Page Settings. + /// + /// [HttpGet("landingpage")] [AllowAnonymous] public async Task LandingPageSettings() @@ -63,12 +94,21 @@ namespace Ombi.Controllers return await Get(); } + /// + /// Save the Landing Page settings. + /// + /// The settings. + /// [HttpPost("landingpage")] public async Task LandingPageSettings([FromBody]LandingPageSettings settings) { return await Save(settings); } + /// + /// Gets the Customization Settings. + /// + /// [HttpGet("customization")] [AllowAnonymous] public async Task CustomizationSettings() @@ -76,32 +116,53 @@ namespace Ombi.Controllers return await Get(); } + /// + /// Save the Customization settings. + /// + /// The settings. + /// [HttpPost("customization")] public async Task CustomizationSettings([FromBody]CustomizationSettings settings) { return await Save(settings); } + /// + /// Gets the Sonarr Settings. + /// + /// [HttpGet("sonarr")] - [AllowAnonymous] public async Task SonarrSettings() { return await Get(); } + /// + /// Save the Sonarr settings. + /// + /// The settings. + /// [HttpPost("sonarr")] public async Task SonarrSettings([FromBody]SonarrSettings settings) { return await Save(settings); } + /// + /// Gets the Radarr Settings. + /// + /// [HttpGet("radarr")] - [AllowAnonymous] public async Task RadarrSettings() { return await Get(); } + /// + /// Save the Radarr settings. + /// + /// The settings. + /// [HttpPost("radarr")] public async Task RadarrSettings([FromBody]RadarrSettings settings) { diff --git a/src/Ombi/Controllers/StatusController.cs b/src/Ombi/Controllers/StatusController.cs index 85d0bd1a7..510cd5e0e 100644 --- a/src/Ombi/Controllers/StatusController.cs +++ b/src/Ombi/Controllers/StatusController.cs @@ -44,6 +44,10 @@ namespace Ombi.Controllers private ISettingsService Ombi { get; } + /// + /// Gets the status of Ombi. + /// + /// [AllowAnonymous] [HttpGet] public HttpStatusCode GetStatus() @@ -52,6 +56,11 @@ namespace Ombi.Controllers } + /// + /// Checks to see if we have run through the wizard + /// + /// + [ApiExplorerSettings(IgnoreApi = true)] [AllowAnonymous] [HttpGet("Wizard")] public async Task WizardStatus() diff --git a/src/Ombi/Ombi.csproj b/src/Ombi/Ombi.csproj index 7530c5e53..c12865cd8 100644 --- a/src/Ombi/Ombi.csproj +++ b/src/Ombi/Ombi.csproj @@ -8,6 +8,10 @@ + + bin\Debug\netcoreapp1.1\Swagger.xml + + @@ -42,6 +46,7 @@ + diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index bfbe339f4..6c256da5d 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.Extensions.PlatformAbstractions; using Ombi.Auth; using Ombi.Config; using Ombi.DependencyInjection; @@ -21,6 +22,7 @@ using Ombi.Mapping; using Ombi.Schedule; using Serilog; using Serilog.Events; +using Swashbuckle.AspNetCore.Swagger; namespace Ombi { @@ -68,7 +70,34 @@ namespace Ombi expression.AddCollectionMappers(); }); services.RegisterDependencies(); // Ioc and EF + services.AddSwaggerGen(c => + { + c.DescribeAllEnumsAsStrings(); + c.SwaggerDoc("v1", new Info + { + Version = "v1", + Title = "Ombi Api", + Description = "The API for Ombi, most of these calls require an auth token that you can get from calling POST:\"api/v1/token/\" with the body of: \n {\n\"username\":\"YOURUSERNAME\",\n\"password\":\"YOURPASSWORD\"\n} \n" + + "You can then use the returned token in the JWT Token field e.g. \"Bearer Token123xxff\"", + Contact = new Contact + { + Email = "tidusjar@gmail.com", + Name = "Jamie Rees", + Url = "https://www.ombi.io/" + } + }); + c.CustomSchemaIds(x => x.FullName); + var basePath = PlatformServices.Default.Application.ApplicationBasePath; + var xmlPath = Path.Combine(basePath, "Swagger.xml"); + c.IncludeXmlComments(xmlPath); + + c.AddSecurityDefinition("Authentication",new ApiKeyScheme()); + c.OperationFilter(); + c.DescribeAllParametersInCamelCase(); + }); + + services.AddSingleton(); services.AddScoped(sp => sp.GetService().HttpContext.User); @@ -103,6 +132,12 @@ namespace Ombi app.UseHangfireServer(); app.UseHangfireDashboard(); + app.UseSwagger(); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); + c.ShowJsonEditor(); + }); // Setup the scheduler diff --git a/src/Ombi/SwaggerOperationFilter.cs b/src/Ombi/SwaggerOperationFilter.cs new file mode 100644 index 000000000..83ebfbc21 --- /dev/null +++ b/src/Ombi/SwaggerOperationFilter.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc.Authorization; +using Swashbuckle.AspNetCore.Swagger; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Ombi +{ + public class SwaggerOperationFilter : IOperationFilter + { + public void Apply(Operation operation, OperationFilterContext context) + { + var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; + var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter); + var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter); + if (isAuthorized && !allowAnonymous) + { + if (operation.Parameters == null) + operation.Parameters = new List(); + operation.Parameters.Add(new NonBodyParameter + { + Name = "Authorization", + In = "header", + Description = "JWT token", + Required = true, + Type = "string", + Default = "Bearer " + }); + } + } + } +}