diff --git a/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs index b8923eef..cd946714 100644 --- a/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs +++ b/src/Kyoo.Abstractions/Models/Attributes/ApiDefinitionAttribute.cs @@ -23,8 +23,10 @@ namespace Kyoo.Abstractions.Models.Attributes { /// /// An attribute to specify on apis to specify it's documentation's name and category. + /// If this is applied on a method, the specified method will be exploded from the controller's page and be + /// included on the specified tag page. /// - [AttributeUsage(AttributeTargets.Class)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class ApiDefinitionAttribute : Attribute { /// diff --git a/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs index 3cad4b6d..bac1edec 100644 --- a/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs +++ b/src/Kyoo.Abstractions/Models/Attributes/Permission/PartialPermissionAttribute.cs @@ -54,14 +54,9 @@ namespace Kyoo.Abstractions.Models.Permissions /// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will /// lead to unspecified behaviors. /// - /// - /// The type of the action - /// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)). - /// + /// The type of the action public PartialPermissionAttribute(string type) { - if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase)) - type = type[..^3]; Type = type.ToLower(); } diff --git a/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs b/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs index 2cf85d2f..cb17020c 100644 --- a/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs +++ b/src/Kyoo.Abstractions/Models/Attributes/Permission/PermissionAttribute.cs @@ -91,17 +91,16 @@ namespace Kyoo.Abstractions.Models.Permissions /// /// /// The type of the action - /// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)). /// - /// The kind of permission needed. + /// + /// The kind of permission needed. + /// /// /// The group of this permission (allow grouped permission like overall.read /// for all read permissions of this group). /// public PermissionAttribute(string type, Kind permission, Group group = Group.Overall) { - if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase)) - type = type[..^3]; Type = type.ToLower(); Kind = permission; Group = group; diff --git a/src/Kyoo.Core/Views/Admin/TaskApi.cs b/src/Kyoo.Core/Views/Admin/TaskApi.cs index 310cad81..dc338c24 100644 --- a/src/Kyoo.Core/Views/Admin/TaskApi.cs +++ b/src/Kyoo.Core/Views/Admin/TaskApi.cs @@ -36,7 +36,7 @@ namespace Kyoo.Core.Api [Route("api/task", Order = AlternativeRoute)] [ApiController] [ResourceView] - [PartialPermission(nameof(TaskApi), Group = Group.Admin)] + [PartialPermission("Task", Group = Group.Admin)] [ApiDefinition("Tasks", Group = AdminGroup)] public class TaskApi : ControllerBase { diff --git a/src/Kyoo.Core/Views/Metadata/GenreApi.cs b/src/Kyoo.Core/Views/Metadata/GenreApi.cs index 57336138..5d3cbf7f 100644 --- a/src/Kyoo.Core/Views/Metadata/GenreApi.cs +++ b/src/Kyoo.Core/Views/Metadata/GenreApi.cs @@ -37,7 +37,7 @@ namespace Kyoo.Core.Api [Route("api/genres")] [Route("api/genre", Order = AlternativeRoute)] [ApiController] - [PartialPermission(nameof(GenreApi))] + [PartialPermission(nameof(Genre))] [ApiDefinition("Genres", Group = MetadataGroup)] public class GenreApi : CrudApi { diff --git a/src/Kyoo.Core/Views/Metadata/ProviderApi.cs b/src/Kyoo.Core/Views/Metadata/ProviderApi.cs index 1150214d..6f9894d5 100644 --- a/src/Kyoo.Core/Views/Metadata/ProviderApi.cs +++ b/src/Kyoo.Core/Views/Metadata/ProviderApi.cs @@ -34,7 +34,7 @@ namespace Kyoo.Core.Api [Route("api/provider", Order = AlternativeRoute)] [ApiController] [ResourceView] - [PartialPermission(nameof(ProviderApi))] + [PartialPermission(nameof(Provider))] [ApiDefinition("Providers", Group = MetadataGroup)] public class ProviderApi : CrudThumbsApi { diff --git a/src/Kyoo.Core/Views/Metadata/StaffApi.cs b/src/Kyoo.Core/Views/Metadata/StaffApi.cs index fc20365a..aea11a4e 100644 --- a/src/Kyoo.Core/Views/Metadata/StaffApi.cs +++ b/src/Kyoo.Core/Views/Metadata/StaffApi.cs @@ -39,7 +39,7 @@ namespace Kyoo.Core.Api [Route("api/people", Order = AlternativeRoute)] [ApiController] [ResourceView] - [PartialPermission(nameof(StaffApi))] + [PartialPermission(nameof(People))] [ApiDefinition("Staff", Group = MetadataGroup)] public class StaffApi : CrudThumbsApi { diff --git a/src/Kyoo.Core/Views/Metadata/StudioApi.cs b/src/Kyoo.Core/Views/Metadata/StudioApi.cs index ae138be3..d5274f18 100644 --- a/src/Kyoo.Core/Views/Metadata/StudioApi.cs +++ b/src/Kyoo.Core/Views/Metadata/StudioApi.cs @@ -37,7 +37,7 @@ namespace Kyoo.Core.Api [Route("api/studios")] [Route("api/studio", Order = AlternativeRoute)] [ApiController] - [PartialPermission(nameof(ShowApi))] + [PartialPermission(nameof(Show))] [ApiDefinition("Studios", Group = MetadataGroup)] public class StudioApi : CrudApi { diff --git a/src/Kyoo.Core/Views/Resources/CollectionApi.cs b/src/Kyoo.Core/Views/Resources/CollectionApi.cs index 89091a7d..c004fc43 100644 --- a/src/Kyoo.Core/Views/Resources/CollectionApi.cs +++ b/src/Kyoo.Core/Views/Resources/CollectionApi.cs @@ -37,7 +37,7 @@ namespace Kyoo.Core.Api [Route("api/collections")] [Route("api/collection", Order = AlternativeRoute)] [ApiController] - [PartialPermission(nameof(CollectionApi))] + [PartialPermission(nameof(Collection))] [ApiDefinition("Collections", Group = ResourcesGroup)] public class CollectionApi : CrudThumbsApi { diff --git a/src/Kyoo.Core/Views/Resources/EpisodeApi.cs b/src/Kyoo.Core/Views/Resources/EpisodeApi.cs index d716dbe7..ba11597a 100644 --- a/src/Kyoo.Core/Views/Resources/EpisodeApi.cs +++ b/src/Kyoo.Core/Views/Resources/EpisodeApi.cs @@ -38,7 +38,7 @@ namespace Kyoo.Core.Api [Route("api/episode", Order = AlternativeRoute)] [ApiController] [ResourceView] - [PartialPermission(nameof(EpisodeApi))] + [PartialPermission(nameof(Episode))] [ApiDefinition("Episodes", Group = ResourcesGroup)] public class EpisodeApi : CrudThumbsApi { diff --git a/src/Kyoo.Core/Views/Resources/LibraryApi.cs b/src/Kyoo.Core/Views/Resources/LibraryApi.cs index d440fae3..4f361705 100644 --- a/src/Kyoo.Core/Views/Resources/LibraryApi.cs +++ b/src/Kyoo.Core/Views/Resources/LibraryApi.cs @@ -40,7 +40,7 @@ namespace Kyoo.Core.Api [Route("api/library", Order = AlternativeRoute)] [ApiController] [ResourceView] - [PartialPermission(nameof(LibraryApi), Group = Group.Admin)] + [PartialPermission(nameof(Library), Group = Group.Admin)] [ApiDefinition("Library", Group = ResourcesGroup)] public class LibraryApi : CrudApi { diff --git a/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs b/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs index 030c60e0..5318d0b5 100644 --- a/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs +++ b/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs @@ -38,6 +38,7 @@ namespace Kyoo.Core.Api [Route("api/item", Order = AlternativeRoute)] [ApiController] [ResourceView] + [PartialPermission(nameof(LibraryItem))] [ApiDefinition("Items", Group = ResourcesGroup)] public class LibraryItemApi : BaseApi { @@ -74,7 +75,7 @@ namespace Kyoo.Core.Api /// The filters or the sort parameters are invalid. /// No library with the given ID or slug could be found. [HttpGet] - [Permission(nameof(LibraryItemApi), Kind.Read)] + [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] diff --git a/src/Kyoo.Core/Views/Resources/SearchApi.cs b/src/Kyoo.Core/Views/Resources/SearchApi.cs new file mode 100644 index 00000000..a22aa85c --- /dev/null +++ b/src/Kyoo.Core/Views/Resources/SearchApi.cs @@ -0,0 +1,194 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System.Collections.Generic; +using System.Threading.Tasks; +using Kyoo.Abstractions.Controllers; +using Kyoo.Abstractions.Models; +using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Abstractions.Models.Permissions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using static Kyoo.Abstractions.Models.Utils.Constants; + +namespace Kyoo.Core.Api +{ + /// + /// An endpoint to search for every resources of kyoo. Searching for only a specific type of resource + /// is available on the said endpoint. + /// + [Route("api/search/{query}")] + [ApiController] + [ResourceView] + [ApiDefinition("Search", Group = ResourcesGroup)] + public class SearchApi : ControllerBase + { + /// + /// The library manager used to modify or retrieve information in the data store. + /// + private readonly ILibraryManager _libraryManager; + + /// + /// Create a new . + /// + /// The library manager used to interact with the data store. + public SearchApi(ILibraryManager libraryManager) + { + _libraryManager = libraryManager; + } + + /// + /// Global search + /// + /// + /// Search for collections, shows, episodes, staff, genre and studios at the same time + /// + /// The query to search for. + /// A list of every resources found for the specified query. + [HttpGet] + [Permission(nameof(Collection), Kind.Read)] + [Permission(nameof(Show), Kind.Read)] + [Permission(nameof(Episode), Kind.Read)] + [Permission(nameof(People), Kind.Read)] + [Permission(nameof(Genre), Kind.Read)] + [Permission(nameof(Studio), Kind.Read)] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task> Search(string query) + { + return new SearchResult + { + Query = query, + Collections = await _libraryManager.Search(query), + Shows = await _libraryManager.Search(query), + Episodes = await _libraryManager.Search(query), + People = await _libraryManager.Search(query), + Genres = await _libraryManager.Search(query), + Studios = await _libraryManager.Search(query) + }; + } + + /// + /// Search collections + /// + /// + /// Search for collections + /// + /// The query to search for. + /// A list of collections found for the specified query. + [HttpGet("collections")] + [HttpGet("collection", Order = AlternativeRoute)] + [Permission(nameof(Collection), Kind.Read)] + [ApiDefinition("Collections")] + [ProducesResponseType(StatusCodes.Status200OK)] + public Task> SearchCollections(string query) + { + return _libraryManager.Search(query); + } + + /// + /// Search shows + /// + /// + /// Search for shows + /// + /// The query to search for. + /// A list of shows found for the specified query. + [HttpGet("shows")] + [HttpGet("show", Order = AlternativeRoute)] + [Permission(nameof(Show), Kind.Read)] + [ApiDefinition("Shows")] + [ProducesResponseType(StatusCodes.Status200OK)] + public Task> SearchShows(string query) + { + return _libraryManager.Search(query); + } + + /// + /// Search episodes + /// + /// + /// Search for episodes + /// + /// The query to search for. + /// A list of episodes found for the specified query. + [HttpGet("episodes")] + [HttpGet("episode", Order = AlternativeRoute)] + [Permission(nameof(Episode), Kind.Read)] + [ApiDefinition("Episodes")] + [ProducesResponseType(StatusCodes.Status200OK)] + public Task> SearchEpisodes(string query) + { + return _libraryManager.Search(query); + } + + /// + /// Search staff + /// + /// + /// Search for staff + /// + /// The query to search for. + /// A list of staff members found for the specified query. + [HttpGet("staff")] + [HttpGet("person", Order = AlternativeRoute)] + [HttpGet("people", Order = AlternativeRoute)] + [Permission(nameof(People), Kind.Read)] + [ApiDefinition("Staff")] + [ProducesResponseType(StatusCodes.Status200OK)] + public Task> SearchPeople(string query) + { + return _libraryManager.Search(query); + } + + /// + /// Search genres + /// + /// + /// Search for genres + /// + /// The query to search for. + /// A list of genres found for the specified query. + [HttpGet("genres")] + [HttpGet("genre", Order = AlternativeRoute)] + [Permission(nameof(Genre), Kind.Read)] + [ApiDefinition("Genres")] + [ProducesResponseType(StatusCodes.Status200OK)] + public Task> SearchGenres(string query) + { + return _libraryManager.Search(query); + } + + /// + /// Search studios + /// + /// + /// Search for studios + /// + /// The query to search for. + /// A list of studios found for the specified query. + [HttpGet("studios")] + [HttpGet("studio", Order = AlternativeRoute)] + [Permission(nameof(Studio), Kind.Read)] + [ApiDefinition("Studios")] + [ProducesResponseType(StatusCodes.Status200OK)] + public Task> SearchStudios(string query) + { + return _libraryManager.Search(query); + } + } +} diff --git a/src/Kyoo.Core/Views/Resources/SeasonApi.cs b/src/Kyoo.Core/Views/Resources/SeasonApi.cs index a92cc256..8f74a08c 100644 --- a/src/Kyoo.Core/Views/Resources/SeasonApi.cs +++ b/src/Kyoo.Core/Views/Resources/SeasonApi.cs @@ -37,7 +37,7 @@ namespace Kyoo.Core.Api [Route("api/seasons")] [Route("api/season", Order = AlternativeRoute)] [ApiController] - [PartialPermission(nameof(SeasonApi))] + [PartialPermission(nameof(Season))] [ApiDefinition("Seasons", Group = ResourcesGroup)] public class SeasonApi : CrudThumbsApi { diff --git a/src/Kyoo.Core/Views/Resources/ShowApi.cs b/src/Kyoo.Core/Views/Resources/ShowApi.cs index 37f3ccd1..46712294 100644 --- a/src/Kyoo.Core/Views/Resources/ShowApi.cs +++ b/src/Kyoo.Core/Views/Resources/ShowApi.cs @@ -44,7 +44,7 @@ namespace Kyoo.Core.Api [Route("api/movie", Order = AlternativeRoute)] [Route("api/movies", Order = AlternativeRoute)] [ApiController] - [PartialPermission(nameof(ShowApi))] + [PartialPermission(nameof(Show))] [ApiDefinition("Shows", Group = ResourcesGroup)] public class ShowApi : CrudThumbsApi { diff --git a/src/Kyoo.Core/Views/SearchApi.cs b/src/Kyoo.Core/Views/SearchApi.cs deleted file mode 100644 index fc180483..00000000 --- a/src/Kyoo.Core/Views/SearchApi.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System.Collections.Generic; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Permissions; -using Microsoft.AspNetCore.Mvc; - -namespace Kyoo.Core.Api -{ - [Route("api/search/{query}")] - [ApiController] - public class SearchApi : ControllerBase - { - private readonly ILibraryManager _libraryManager; - - public SearchApi(ILibraryManager libraryManager) - { - _libraryManager = libraryManager; - } - - [HttpGet] - [Permission(nameof(Collection), Kind.Read)] - [Permission(nameof(Show), Kind.Read)] - [Permission(nameof(Episode), Kind.Read)] - [Permission(nameof(People), Kind.Read)] - [Permission(nameof(Genre), Kind.Read)] - [Permission(nameof(Studio), Kind.Read)] - public async Task> Search(string query) - { - return new SearchResult - { - Query = query, - Collections = await _libraryManager.Search(query), - Shows = await _libraryManager.Search(query), - Episodes = await _libraryManager.Search(query), - People = await _libraryManager.Search(query), - Genres = await _libraryManager.Search(query), - Studios = await _libraryManager.Search(query) - }; - } - - [HttpGet("collection")] - [HttpGet("collections")] - [Permission(nameof(Collection), Kind.Read)] - public Task> SearchCollections(string query) - { - return _libraryManager.Search(query); - } - - [HttpGet("show")] - [HttpGet("shows")] - [Permission(nameof(Show), Kind.Read)] - public Task> SearchShows(string query) - { - return _libraryManager.Search(query); - } - - [HttpGet("episode")] - [HttpGet("episodes")] - [Permission(nameof(Episode), Kind.Read)] - public Task> SearchEpisodes(string query) - { - return _libraryManager.Search(query); - } - - [HttpGet("people")] - [Permission(nameof(People), Kind.Read)] - public Task> SearchPeople(string query) - { - return _libraryManager.Search(query); - } - - [HttpGet("genre")] - [HttpGet("genres")] - [Permission(nameof(Genre), Kind.Read)] - public Task> SearchGenres(string query) - { - return _libraryManager.Search(query); - } - - [HttpGet("studio")] - [HttpGet("studios")] - [Permission(nameof(Studio), Kind.Read)] - public Task> SearchStudios(string query) - { - return _libraryManager.Search(query); - } - } -} diff --git a/src/Kyoo.Swagger/ApiSorter.cs b/src/Kyoo.Swagger/ApiSorter.cs index f328d354..233151a6 100644 --- a/src/Kyoo.Swagger/ApiSorter.cs +++ b/src/Kyoo.Swagger/ApiSorter.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Linq; +using Kyoo.Swagger.Models; using NSwag; using NSwag.Generation.AspNetCore; @@ -49,13 +50,16 @@ namespace Kyoo.Swagger { if (!postProcess.ExtensionData.TryGetValue("x-tagGroups", out object list)) return; - List tagGroups = (List)list; + List tagGroups = (List)list; postProcess.ExtensionData["x-tagGroups"] = tagGroups - .OrderBy(x => x.name) - .Select(x => new + .OrderBy(x => x.Name) + .Select(x => { - name = x.name.Substring(x.name.IndexOf(':') + 1), - x.tags + x.Name = x.Name[(x.Name.IndexOf(':') + 1)..]; + x.Tags = x.Tags + .OrderBy(y => y) + .ToList(); + return x; }) .ToList(); }; diff --git a/src/Kyoo.Swagger/ApiTagsFilter.cs b/src/Kyoo.Swagger/ApiTagsFilter.cs index 9ee21a01..10177e71 100644 --- a/src/Kyoo.Swagger/ApiTagsFilter.cs +++ b/src/Kyoo.Swagger/ApiTagsFilter.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Kyoo.Abstractions.Models.Attributes; +using Kyoo.Swagger.Models; using Namotion.Reflection; using NSwag; using NSwag.Generation.AspNetCore; @@ -44,6 +45,10 @@ namespace Kyoo.Swagger ApiDefinitionAttribute def = context.ControllerType.GetCustomAttribute(); string name = def?.Name ?? context.ControllerType.Name; + ApiDefinitionAttribute methodOverride = context.MethodInfo.GetCustomAttribute(); + if (methodOverride != null) + name = methodOverride.Name; + context.OperationDescription.Operation.Tags.Add(name); if (context.Document.Tags.All(x => x.Name != name)) { @@ -58,20 +63,20 @@ namespace Kyoo.Swagger return true; context.Document.ExtensionData ??= new Dictionary(); - context.Document.ExtensionData.TryAdd("x-tagGroups", new List()); - List obj = (List)context.Document.ExtensionData["x-tagGroups"]; - dynamic existing = obj.FirstOrDefault(x => x.name == def.Group); + context.Document.ExtensionData.TryAdd("x-tagGroups", new List()); + List obj = (List)context.Document.ExtensionData["x-tagGroups"]; + TagGroups existing = obj.FirstOrDefault(x => x.Name == def.Group); if (existing != null) { - if (!existing.tags.Contains(def.Name)) - existing.tags.Add(def.Name); + if (!existing.Tags.Contains(def.Name)) + existing.Tags.Add(def.Name); } else { - obj.Add(new + obj.Add(new TagGroups { - name = def.Group, - tags = new List { def.Name } + Name = def.Group, + Tags = new List { def.Name } }); } @@ -88,19 +93,19 @@ namespace Kyoo.Swagger /// public static void AddLeftoversToOthersGroup(this OpenApiDocument postProcess) { - List tagGroups = (List)postProcess.ExtensionData["x-tagGroups"]; + List tagGroups = (List)postProcess.ExtensionData["x-tagGroups"]; List tagsWithoutGroup = postProcess.Tags .Select(x => x.Name) .Where(x => tagGroups - .SelectMany(y => y.tags) + .SelectMany(y => y.Tags) .All(y => y != x)) .ToList(); if (tagsWithoutGroup.Any()) { - tagGroups.Add(new + tagGroups.Add(new TagGroups { - name = "Others", - tags = tagsWithoutGroup + Name = "Others", + Tags = tagsWithoutGroup }); } } diff --git a/src/Kyoo.Swagger/Models/TagGroups.cs b/src/Kyoo.Swagger/Models/TagGroups.cs new file mode 100644 index 00000000..d04df266 --- /dev/null +++ b/src/Kyoo.Swagger/Models/TagGroups.cs @@ -0,0 +1,42 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System.Collections.Generic; +using Newtonsoft.Json; +using NSwag; + +namespace Kyoo.Swagger.Models +{ + /// + /// A class representing a group of tags in the + /// + public class TagGroups + { + /// + /// The name of the tag group. + /// + [JsonProperty(PropertyName = "name")] + public string Name { get; set; } + + /// + /// The list of tags in this group. + /// + [JsonProperty(PropertyName = "tags")] + public List Tags { get; set; } + } +}