diff --git a/Controllers/v1/AlbumController.cs b/Controllers/v1/AlbumController.cs index 8a3a259..7980f71 100644 --- a/Controllers/v1/AlbumController.cs +++ b/Controllers/v1/AlbumController.cs @@ -39,7 +39,7 @@ namespace Icarus.Controllers.V1 #region HTTP Routes [HttpGet] - public IActionResult Get() + public IActionResult GetAlbums() { List albums = new List(); @@ -54,7 +54,7 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetAlbum(int id) { Album album = new Album { diff --git a/Controllers/v1/ArtistController.cs b/Controllers/v1/ArtistController.cs index a27f48a..219e6c5 100644 --- a/Controllers/v1/ArtistController.cs +++ b/Controllers/v1/ArtistController.cs @@ -38,7 +38,7 @@ namespace Icarus.Controllers.V1 #region HTTP Routes [HttpGet] - public IActionResult Get() + public IActionResult GetArtists() { var artistContext = new ArtistContext(_connectionString); @@ -51,7 +51,7 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetArtist(int id) { if (!IsTokenValid("read:artists")) { diff --git a/Controllers/v1/BaseController.cs b/Controllers/v1/BaseController.cs index 911d273..9cec68a 100644 --- a/Controllers/v1/BaseController.cs +++ b/Controllers/v1/BaseController.cs @@ -17,6 +17,7 @@ namespace Icarus.Controllers.V1 #region Methods + [ApiExplorerSettings(IgnoreApi = true)] protected string ParseBearerTokenFromHeader() { var token = string.Empty; @@ -37,6 +38,7 @@ namespace Icarus.Controllers.V1 return token; } + [ApiExplorerSettings(IgnoreApi = true)] protected bool IsTokenValid(string scope) { var token = ParseBearerTokenFromHeader(); diff --git a/Controllers/v1/CoverArtController.cs b/Controllers/v1/CoverArtController.cs index 2dd422a..4d3ef29 100644 --- a/Controllers/v1/CoverArtController.cs +++ b/Controllers/v1/CoverArtController.cs @@ -35,7 +35,8 @@ namespace Icarus.Controllers.V1 #region HTTP Routes - public IActionResult Get() + [HttpGet] + public IActionResult GetCoverArts() { var coverArtContext = new CoverArtContext(_connectionString); @@ -54,7 +55,7 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public async Task Get(int id) + public IActionResult GetCoverArt(int id) { var coverArt = new CoverArt { CoverArtID = id }; @@ -65,7 +66,7 @@ namespace Icarus.Controllers.V1 if (coverArt != null) { _logger.LogInformation("Found cover art record"); - var coverArtBytes = await System.IO.File.ReadAllBytesAsync( + var coverArtBytes = System.IO.File.ReadAllBytes( coverArt.ImagePath); return File(coverArtBytes, "application/x-msdownload", diff --git a/Controllers/v1/GenreController.cs b/Controllers/v1/GenreController.cs index ae553e6..d5a86c1 100644 --- a/Controllers/v1/GenreController.cs +++ b/Controllers/v1/GenreController.cs @@ -39,7 +39,7 @@ namespace Icarus.Controllers.V1 #region HTTP Routes [HttpGet] - public IActionResult Get() + public IActionResult GetGenres() { var genres = new List(); @@ -54,7 +54,7 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetGenre(int id) { var genre = new Genre { diff --git a/Controllers/v1/LoginController.cs b/Controllers/v1/LoginController.cs index 0458b4c..8446063 100644 --- a/Controllers/v1/LoginController.cs +++ b/Controllers/v1/LoginController.cs @@ -38,7 +38,8 @@ namespace Icarus.Controllers.V1 #region HTTP endpoints - public IActionResult Post([FromBody] User user) + [HttpPost] + public IActionResult Login([FromBody] User user) { var context = new UserContext(_connectionString); diff --git a/Controllers/v1/RegisterController.cs b/Controllers/v1/RegisterController.cs index e1352d8..202b728 100644 --- a/Controllers/v1/RegisterController.cs +++ b/Controllers/v1/RegisterController.cs @@ -37,7 +37,7 @@ namespace Icarus.Controllers.V1 #endregion [HttpPost] - public IActionResult Post([FromBody] User user) + public IActionResult RegisterUser([FromBody] User user) { PasswordEncryption pe = new PasswordEncryption(); user.Password = pe.HashPassword(user); diff --git a/Controllers/v1/SongCompressedDataControllers.cs b/Controllers/v1/SongCompressedDataControllers.cs index 6045caf..789a5d4 100644 --- a/Controllers/v1/SongCompressedDataControllers.cs +++ b/Controllers/v1/SongCompressedDataControllers.cs @@ -46,7 +46,7 @@ namespace Icarus.Controllers.V1 #region API Routes [HttpGet("{id}")] - public async Task Get(int id) + public async Task DownloadCompressedSong(int id) { var context = new SongContext(_connectionString); diff --git a/Controllers/v1/SongController.cs b/Controllers/v1/SongController.cs index 05cc9f2..c7ebe3d 100644 --- a/Controllers/v1/SongController.cs +++ b/Controllers/v1/SongController.cs @@ -48,7 +48,7 @@ namespace Icarus.Controllers.V1 [HttpGet] - public IActionResult Get() + public IActionResult GetSongs() { List songs = new List(); Console.WriteLine("Attemtping to retrieve songs"); @@ -65,7 +65,7 @@ namespace Icarus.Controllers.V1 } [HttpGet("{id}")] - public IActionResult Get(int id) + public IActionResult GetSong(int id) { var context = new SongContext(_connectionString); @@ -81,7 +81,7 @@ namespace Icarus.Controllers.V1 } [HttpPut("{id}")] - public IActionResult Put(int id, [FromBody] Song song) + public IActionResult UpdateSong(int id, [FromBody] Song song) { var context = new SongContext(_connectionString); diff --git a/Controllers/v1/SongDataController.cs b/Controllers/v1/SongDataController.cs index ab64a50..48341b6 100644 --- a/Controllers/v1/SongDataController.cs +++ b/Controllers/v1/SongDataController.cs @@ -48,13 +48,12 @@ namespace Icarus.Controllers.V1 [HttpGet("download/{id}")] - [Route("private-scoped")] - public async Task Get(int id) + public IActionResult Download(int id) { var songContext = new SongContext(_connectionString); var songMetaData = songContext.RetrieveRecord(new Song { SongID = id}); - var song = await _songMgr.RetrieveSong(songMetaData); + var song = _songMgr.RetrieveSong(songMetaData).Result; return File(song.Data, "application/x-msdownload", songMetaData.Filename); } @@ -72,8 +71,7 @@ namespace Icarus.Controllers.V1 // Cover art // [HttpPost("upload"), DisableRequestSizeLimit] - [Route("private-scoped")] - public IActionResult Post([FromForm(Name = "file")] List songData) + public IActionResult Upload([FromForm(Name = "file")] List songData) { try { @@ -109,8 +107,7 @@ namespace Icarus.Controllers.V1 // as well as the cover art // [HttpPost("upload/with/data")] - [Route("private-scoped")] - public IActionResult Post ([FromForm] UploadSongWithDataForm up) + public IActionResult UploadWithData([FromForm] UploadSongWithDataForm up) { try { @@ -131,7 +128,7 @@ namespace Icarus.Controllers.V1 } [HttpDelete("delete/{id}")] - public IActionResult Delete(int id) + public IActionResult DeleteSong(int id) { var songContext = new SongContext(_connectionString); @@ -156,15 +153,15 @@ namespace Icarus.Controllers.V1 } - public class UploadSongWithDataForm - { - [FromForm(Name = "file")] - public IFormFile SongData { get; set; } - // TODO: Think about making this optional and if it is not provided, use the stock cover art - [FromForm(Name = "cover")] - public IFormFile CoverArtData { get; set; } - [FromForm(Name = "metadata")] - public string SongFile { get; set; } - } + public class UploadSongWithDataForm + { + [FromForm(Name = "file")] + public IFormFile SongData { get; set; } + // NOTE: Think about making this optional and if it is not provided, use the stock cover art + [FromForm(Name = "cover")] + public IFormFile CoverArtData { get; set; } + [FromForm(Name = "metadata")] + public string SongFile { get; set; } + } } } diff --git a/Controllers/v1/SongStreamController.cs b/Controllers/v1/SongStreamController.cs index 967a74b..de92076 100644 --- a/Controllers/v1/SongStreamController.cs +++ b/Controllers/v1/SongStreamController.cs @@ -45,7 +45,7 @@ namespace Icarus.Controllers.V1 #region HTTP endpoints [HttpGet("{id}")] - public async Task Get(int id) + public async Task StreamSong(int id) { var context = new SongContext(_config.GetConnectionString("DefaultConnection")); diff --git a/Icarus.csproj b/Icarus.csproj index 628bbcb..7e626cd 100644 --- a/Icarus.csproj +++ b/Icarus.csproj @@ -25,6 +25,7 @@ + diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 82a1227..b71d9cb 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -12,7 +12,7 @@ "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -20,7 +20,8 @@ "Icarus": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "api/values", + "dotnetRuneMessage": true, + "launchUrl": "swagger", "applicationUrl": "http://localhost:5002", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" diff --git a/README.md b/README.md index d57c2e5..c3bb084 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,9 @@ One can interface with Icarus the music server either by: ## Getting started There are several things that need to be completed to properly setup and secure the API. -#### 1. Creating RSA keys +This API uses OpenAPI Specification 3.0. After configuring the API, launch the software +and navigate your browser to https://localhost:5001/swagger to view the endpoints. + 1. JWT Information 2. API filesystem paths 3. Database connection string @@ -138,11 +140,6 @@ From this point the database has been successfully configured. Metadata and song Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduct, and the process for submitting pull requests to the project. -## Authors - -* [kdeng00](https://github.com/kdeng00) - -See also the list of [contributors](https://github.com/amazing-username/Icarus/graphs/contributors) who participated in this project. ## License diff --git a/Startup.cs b/Startup.cs index 88603bd..89c50d1 100644 --- a/Startup.cs +++ b/Startup.cs @@ -1,15 +1,18 @@ using System; using System.Text; +using System.Linq; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using Newtonsoft.Json; using NLog; using NLog.Web; @@ -68,12 +71,48 @@ namespace Icarus services.AddControllers() .AddNewtonsoftJson(); + + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(c => + { + c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); + + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Icarus", Version = "v1" }); + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() + { + Name = "Authorization", + Scheme = "Bearer", + BearerFormat = "JWT", + Type = SecuritySchemeType.ApiKey, + In = ParameterLocation.Header, + Description = "Bearer *Auth Token*", + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new string[] {} + } + }); + }); } // Called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // NOTE: Dev-related configuration can be done when env.IsDevelopment() evaluated to true + if (env.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } app.UseRouting(); app.UseAuthentication();