diff --git a/backend/Controllers/MovieController.cs b/backend/Controllers/MovieController.cs index b58c0a8..c720c66 100644 --- a/backend/Controllers/MovieController.cs +++ b/backend/Controllers/MovieController.cs @@ -1,29 +1,90 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.OpenApi.Writers; -namespace backend.Controllers; +namespace backend; +using static backend.QueryParameterValidators; [ApiController] [Route("[controller]")] public class MovieController: ControllerBase { + private readonly MovieDbContext _context; private readonly ILogger _logger; + private static readonly string[] sortTypes = new[] + { + "titleasc", "titledesc", "yearasc", "yeardesc" + }; - public MovieController(ILogger logger) + public MovieController(ILogger logger, MovieDbContext context) { _logger = logger; + _context = context; } - [HttpGet(Name = "GetMovie")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new Movie + [HttpGet(Name = "GetMovies")] + public ActionResult> Get( + [FromQuery] string s, + [FromQuery] string? type, + [FromQuery] string? y, + [FromQuery] string? sort, + [FromQuery] int pageNumber = 1, + [FromQuery] int pageSize = 5 + ) { + try { - Title = "Title", - Year = "Year", - imdbID = "imdbID", - Type = "Type", - Poster = "Poster" - }) - .ToArray(); + if (!IsValidS(s)) return StatusCode(400, "Bad Request: Invalid title"); + var movies = _context.Movies.Where(m => m.Title.ToLower().Contains(s.ToLower())); + + if (type != null) { + if (!IsValidType(type)) return StatusCode(400, "Bad Request: Invalid type"); + movies = movies.Where(m => m.Type == type); + } + + if (y != null) { + if (!IsValidYear(y)) return StatusCode(400, "Bad Request: Invalid year"); + movies = movies.Where(m => m.Year == y); + } + + if (sort != null) { + if (!IsValidSort(sort)) return StatusCode(400, "Bad Request: Invalid sort-type"); + if (sort == "titleasc") movies = movies.OrderBy(m => m.Title); + if (sort == "titledesc") movies = movies.OrderByDescending(m => m.Title); + if (sort == "yearasc") movies = movies.OrderBy(m => m.Year); + if (sort == "yeardesc") movies = movies.OrderByDescending(m => m.Year); + } + + + if (!IsValidPageNumber(pageNumber) || !IsValidPageSize(pageSize)) + return StatusCode(400, "Bad Request: Invalid page-size or page-number"); + + var totalMovies = movies.Count(); + var totalPages = Math.Ceiling((double)totalMovies / pageSize); + + IEnumerable resultSkip = movies.Skip(pageSize * (pageNumber - 1)); + IEnumerable resultTake = resultSkip.Take(pageSize); + + if (resultTake.ToList().Count == 0) { + return StatusCode(204, "No Content"); + } + + return Ok(resultTake); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error fetching movies"); + return StatusCode(500, "Internal server error"); + } } + + // [HttpPost(Name = "PostMovie")] + // public ActionResult<> Post([FromQuery] string movieTitle) { + // try + // { + + // } + // catch (Exception ex) + // { + + // } + // } } \ No newline at end of file diff --git a/backend/Controllers/WeatherForecastController.cs b/backend/Controllers/WeatherForecastController.cs deleted file mode 100644 index 44d1739..0000000 --- a/backend/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace backend.Controllers; - -[ApiController] -[Route("[controller]")] -public class WeatherForecastController : ControllerBase -{ - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } -} diff --git a/backend/Util/Validators.cs b/backend/Util/Validators.cs new file mode 100644 index 0000000..77b9a57 --- /dev/null +++ b/backend/Util/Validators.cs @@ -0,0 +1,56 @@ +namespace backend; + +public static class QueryParameterValidators +{ + private static readonly string[] sortTypes = new[] + { + "titleasc", "titledesc", "yearasc", "yeardesc" + }; + + private static readonly string[] movieTypes = new[] + { + "movie", "series", "episode" + }; + + + // Assuming `s` is a non-nullable parameter and can be any string + // If there are specific requirements for `s`, additional validation can be added + public static bool IsValidS(string s) + { + return !string.IsNullOrWhiteSpace(s); + } + + // Assuming `type` can be any string but you might want to limit it to specific values + // If there are predefined types, you can replace the body with something like: return new List { "type1", "type2" }.Contains(type); + public static bool IsValidType(string? type) + { + return string.IsNullOrWhiteSpace(type) || movieTypes.Contains(type.ToLower()); + } + + // For `year`, assuming it's a 4 digit representation of a year + public static bool IsValidYear(string? year) + { + if (string.IsNullOrWhiteSpace(year)) return true; + + return int.TryParse(year, out int parsedYear) && parsedYear > 1900 && parsedYear <= DateTime.Now.Year; + } + + // Assuming `sort` can be any string but you might want to limit it to specific values + // If there are predefined sorts, you can replace the body with something like: return new List { "asc", "desc" }.Contains(sort); + public static bool IsValidSort(string? sort) + { + return string.IsNullOrWhiteSpace(sort) || sortTypes.Contains(sort.ToLower()); + } + + // Assuming `pageNumber` should be 1 or more + public static bool IsValidPageNumber(int pageNumber) + { + return pageNumber > 0; + } + + // Assuming `pageSize` should be between 1 to 100 (or any other limits you might want to set) + public static bool IsValidPageSize(int pageSize) + { + return pageSize > 0 && pageSize <= 100; // you can adjust the upper limit as per requirements + } +} \ No newline at end of file diff --git a/backend/openapi.yaml b/backend/openapi.yaml new file mode 100644 index 0000000..81bb8aa --- /dev/null +++ b/backend/openapi.yaml @@ -0,0 +1,196 @@ +swagger: '2.0' +info: + description: 'This API is made for our task for WA.works.' + version: '1.0' + title: Cinemateket API + license: + name: Github-repository + url: https://github.com/SindreKjelsrud/Cinemateket/ +host: github.com +basePath: '/SindreKjelsrud/Cinemateket/' +tags: + - name: Search Parameter + description: e.g. ?s=title +schemes: + - http + - https +paths: + '/?s': + get: + tags: + - Search Parameter + summary: Returns an array of results for a given title + operationId: titleSearch + parameters: + - name: s + in: query + description: Title of movie or series + required: true + type: string + - name: y + in: query + description: Year of release + required: false + type: integer + - name: type + in: query + description: Return movie or series + required: false + type: string + enum: + - movie + - series + - name: sort + in: query + description: Choose sorted order to return + required: false + type: string + enum: + - titleasc + - titledesc + - yearasc + - yeardesc + - name: pageNumber + in: query + description: Page number to return + required: false + type: integer + - name: pageSize + in: query + description: Size of pages to return + type: integer + responses: + '200': + description: Successful operation + '204': + description: No content + '400': + description: Bad request + '500': + description: Internal server error + post: + tags: + - Search Parameter + summary: Inserts a new movie to the database + operationId: titleSearch + parameters: + - name: s + in: query + description: Title of movie or series + required: true + type: string + - name: y + in: query + description: Year of release + required: false + type: integer + - name: type + in: query + description: Return movie or series + required: false + type: string + enum: + - movie + - series + - name: pageNumber + in: query + description: Page number to return + required: false + type: integer + - name: pageSize + in: query + description: Size of pages to return + type: integer + responses: + '200': + description: Successful operation + '204': + description: No content + '400': + description: Bad request + '500': + description: Internal server error + put: + tags: + - Search Parameter + summary: Make changes to an existing movie + operationId: titleSearch + parameters: + - name: s + in: query + description: Title of movie or series + required: true + type: string + - name: y + in: query + description: Year of release + required: false + type: integer + - name: type + in: query + description: Return movie or series + required: false + type: string + enum: + - movie + - series + - name: pageNumber + in: query + description: Page number to return + required: false + type: integer + - name: pageSize + in: query + description: Size of pages to return + type: integer + responses: + '200': + description: Successful operation + '204': + description: No content + '400': + description: Bad request + '500': + description: Internal server error + delete: + tags: + - Search Parameter + summary: Deletes a movie with a given title or imdbID + operationId: titleSearch + parameters: + - name: s + in: query + description: Title of movie or series + required: true + type: string + - name: y + in: query + description: Year of release + required: false + type: integer + - name: type + in: query + description: Return movie or series + required: false + type: string + enum: + - movie + - series + - name: pageNumber + in: query + description: Page number to return + required: false + type: integer + - name: pageSize + in: query + description: Size of pages to return + type: integer + responses: + '200': + description: Successful operation + '204': + description: No content + '400': + description: Bad request + '500': + description: Internal server error