mirror of
https://github.com/sphildreth/roadie
synced 2025-02-17 21:48:27 +00:00
v20190317.1
This commit is contained in:
parent
ca98411c68
commit
a876eec82b
15 changed files with 205 additions and 81 deletions
Inspector
Roadie.Api.Library.Tests
Roadie.Api.Library
Roadie.Api.Services
AdminService.csITrackService.csImageService.csReleaseService.csRoadie.Api.Services.csprojTrackService.cs
Roadie.Api
|
@ -16,7 +16,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.3" />
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
|
|
@ -68,6 +68,15 @@ namespace Roadie.Library.Data
|
|||
return FolderPathHelper.PathForTrack(configuration, this, libraryFolder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full file path to the current track thumbnail (if any)
|
||||
/// </summary>
|
||||
public string PathToTrackThumbnail(IRoadieSettings configuration, string libraryFolder)
|
||||
{
|
||||
return FolderPathHelper.PathForTrackThumbnail(configuration, this, libraryFolder);
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Id [{0}], TrackNumber [{1}], Title [{2}]", this.Id, this.TrackNumber, this.Title);
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Roadie.Library.Enums
|
|||
ArtistSecondary,
|
||||
Release,
|
||||
ReleaseSecondary,
|
||||
Label
|
||||
Label,
|
||||
Track
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ namespace Roadie.Library.Models
|
|||
[MaxLength(100)]
|
||||
public string MusicBrainzId { get; set; }
|
||||
|
||||
// When populated a "data:image" base64 byte array of an image to use as new Thumbnail
|
||||
public string NewThumbnailData { get; set; }
|
||||
|
||||
[MaxLength(65535)]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
|
@ -65,7 +68,7 @@ namespace Roadie.Library.Models
|
|||
{
|
||||
return null;
|
||||
}
|
||||
return this.PartTitles.Split('|');
|
||||
return this.PartTitles.Replace("|", "\n").Split("\n");
|
||||
}
|
||||
return this._partTitles;
|
||||
}
|
||||
|
|
|
@ -9,20 +9,20 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="12.1.2" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.3" />
|
||||
<PackageReference Include="FluentFTP" Version="23.1.0" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.6" />
|
||||
<PackageReference Include="FluentFTP" Version="24.0.0" />
|
||||
<PackageReference Include="Hashids.net" Version="1.2.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.9.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.4" />
|
||||
<PackageReference Include="IdSharp.Common" Version="1.0.1" />
|
||||
<PackageReference Include="IdSharp.Tagging" Version="1.0.0-rc3" />
|
||||
<PackageReference Include="Inflatable.Lastfm" Version="1.1.0.339" />
|
||||
<PackageReference Include="Mapster" Version="3.3.2" />
|
||||
<PackageReference Include="Mapster" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
<PackageReference Include="MimeMapping" Version="1.0.1.12" />
|
||||
<PackageReference Include="NodaTime" Version="2.4.4" />
|
||||
<PackageReference Include="NodaTime" Version="2.4.5" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
||||
<PackageReference Include="RestSharp" Version="106.6.9" />
|
||||
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0006" />
|
||||
|
@ -32,7 +32,7 @@
|
|||
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.5.0" />
|
||||
<PackageReference Include="System.Runtime.Caching" Version="4.5.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="2.6.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="2.9.0" />
|
||||
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -82,6 +82,24 @@ namespace Roadie.Library.Utility
|
|||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For a given Track database record determine the full path to the thumbnail using the given destination folder
|
||||
/// </summary>
|
||||
/// <param name="track">Populate track database record</param>
|
||||
/// <param name="destinationFolder">Optional Root folder defaults to Library Folder from Settings</param>
|
||||
public static string PathForTrackThumbnail(IRoadieSettings configuration, Data.Track track, string destinationFolder = null)
|
||||
{
|
||||
destinationFolder = destinationFolder ?? configuration.LibraryFolder;
|
||||
if (string.IsNullOrEmpty(track.FilePath) || string.IsNullOrEmpty(track.FileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var fileName = Path.ChangeExtension(track.FileName, ".jpg");
|
||||
var directoryInfo = new DirectoryInfo(Path.Combine(destinationFolder, track.FilePath, fileName));
|
||||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Full path to Release folder using given full Artist folder
|
||||
/// </summary>
|
||||
|
|
|
@ -191,6 +191,12 @@ namespace Roadie.Api.Services
|
|||
File.Delete(trackPath);
|
||||
this.Logger.LogWarning($"x For Track `{ track }`, Deleted File [{ trackPath }]");
|
||||
}
|
||||
var trackThumbnailName = track.PathToTrackThumbnail(this.Configuration, this.Configuration.LibraryFolder);
|
||||
if (File.Exists(trackThumbnailName))
|
||||
{
|
||||
File.Delete(trackThumbnailName);
|
||||
this.Logger.LogWarning($"x For Track `{ track }`, Deleted Thumbnail File [{ trackThumbnailName }]");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
|
||||
|
||||
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
|
||||
|
||||
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
|
||||
|
||||
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser);
|
||||
|
|
|
@ -379,37 +379,45 @@ namespace Roadie.Api.Services
|
|||
|
||||
private async Task<FileOperationResult<Image>> GetImageFileOperation(string type, string regionUrn, Guid id, int? width, int? height, Func<Task<FileOperationResult<Image>>> action, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = (await this.CacheManager.GetAsync($"urn:{ type }_by_id_operation:{id}", action, regionUrn)).Adapt<FileOperationResult<Image>>();
|
||||
if (!result.IsSuccess)
|
||||
try
|
||||
{
|
||||
return new FileOperationResult<Image>(result.IsNotFoundResult, result.Messages);
|
||||
}
|
||||
if (result.ETag == etag)
|
||||
{
|
||||
return new FileOperationResult<Image>(OperationMessages.NotModified);
|
||||
}
|
||||
if ((width.HasValue || height.HasValue) && result?.Data?.Bytes != null)
|
||||
{
|
||||
result.Data.Bytes = ImageHelper.ResizeImage(result?.Data?.Bytes, width.Value, height.Value);
|
||||
result.ETag = EtagHelper.GenerateETag(this.HttpEncoder, result.Data.Bytes);
|
||||
result.LastModified = DateTime.UtcNow;
|
||||
if (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height)
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = (await this.CacheManager.GetAsync($"urn:{ type }_by_id_operation:{id}", action, regionUrn)).Adapt<FileOperationResult<Image>>();
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
this.Logger.LogTrace($"{ type }: Resized [{ id }], Width [{ width.Value }], Height [{ height.Value }]");
|
||||
return new FileOperationResult<Image>(result.IsNotFoundResult, result.Messages);
|
||||
}
|
||||
if (result.ETag == etag)
|
||||
{
|
||||
return new FileOperationResult<Image>(OperationMessages.NotModified);
|
||||
}
|
||||
if ((width.HasValue || height.HasValue) && result?.Data?.Bytes != null)
|
||||
{
|
||||
result.Data.Bytes = ImageHelper.ResizeImage(result?.Data?.Bytes, width.Value, height.Value);
|
||||
result.ETag = EtagHelper.GenerateETag(this.HttpEncoder, result.Data.Bytes);
|
||||
result.LastModified = DateTime.UtcNow;
|
||||
if (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height)
|
||||
{
|
||||
this.Logger.LogTrace($"{ type }: Resized [{ id }], Width [{ width.Value }], Height [{ height.Value }]");
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
return new FileOperationResult<Image>(result.Messages)
|
||||
{
|
||||
Data = result.Data,
|
||||
ETag = result.ETag,
|
||||
LastModified = result.LastModified,
|
||||
ContentType = result.ContentType,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
sw.Stop();
|
||||
return new FileOperationResult<Image>(result.Messages)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Data = result.Data,
|
||||
ETag = result.ETag,
|
||||
LastModified = result.LastModified,
|
||||
ContentType = result.ContentType,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
this.Logger.LogError(ex, $"GetImageFileOperation Error, Type [{ type }], id [{id}]");
|
||||
}
|
||||
return new FileOperationResult<Image>("System Error");
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> ImageByIdAction(Guid id, EntityTagHeaderValue etag = null)
|
||||
|
@ -663,6 +671,12 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
return new FileOperationResult<Image>(true, string.Format("Track Not Found [{0}]", id));
|
||||
}
|
||||
var imageBytes = track.Thumbnail;
|
||||
var trackThumbnailImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(track.PathToTrackThumbnail(this.Configuration, this.Configuration.LibraryFolder)), Library.Enums.ImageType.Track, SearchOption.TopDirectoryOnly);
|
||||
if (trackThumbnailImages.Any())
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(trackThumbnailImages.First().FullName);
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = track.Thumbnail,
|
||||
|
|
|
@ -425,53 +425,34 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
if (includes.Contains("tracks"))
|
||||
{
|
||||
var releaseIds = rows.Select(x => x.Id).ToArray();
|
||||
var artistTracks = (from r in this.DbContext.Releases
|
||||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
||||
join a in this.DbContext.Artists on r.ArtistId equals a.Id
|
||||
where (releaseIds.Contains(r.RoadieId))
|
||||
orderby r.Id, rm.MediaNumber, t.TrackNumber
|
||||
select new
|
||||
{
|
||||
t,
|
||||
releaseMedia = rm,
|
||||
release = r
|
||||
});
|
||||
var releaseTrackIds = artistTracks.Select(x => x.t.Id).ToList();
|
||||
var artistUserTracks = (from ut in this.DbContext.UserTracks
|
||||
where ut.UserId == roadieUser.Id
|
||||
where (from x in releaseTrackIds select x).Contains(ut.TrackId)
|
||||
select ut).ToArray();
|
||||
var user = this.GetUser(roadieUser.UserId);
|
||||
foreach (var release in rows)
|
||||
{
|
||||
var releaseMedias = new List<ReleaseMediaList>();
|
||||
foreach (var releaseMedia in artistTracks.Where(x => x.release.RoadieId == release.Id).Select(x => x.releaseMedia).Distinct().ToArray())
|
||||
release.Media = this.DbContext.ReleaseMedias
|
||||
.Include(x => x.Tracks)
|
||||
.Where(x => x.ReleaseId == release.DatabaseId)
|
||||
.ProjectToType<ReleaseMediaList>()
|
||||
.OrderBy(x => x.MediaNumber)
|
||||
.ToArray();
|
||||
|
||||
var userRatingsForRelease = (from ut in this.DbContext.UserTracks
|
||||
join t in this.DbContext.Tracks on ut.TrackId equals t.Id
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == release.DatabaseId
|
||||
where ut.UserId == roadieUser.Id
|
||||
select new { trackId = t.RoadieId, ut }).ToArray();
|
||||
foreach (var userRatingForRelease in userRatingsForRelease)
|
||||
{
|
||||
var rm = releaseMedia.Adapt<ReleaseMediaList>();
|
||||
var rmTracks = new List<TrackList>();
|
||||
foreach (var track in artistTracks.Where(x => x.t.ReleaseMediaId == releaseMedia.Id).OrderBy(x => x.t.TrackNumber).ToArray())
|
||||
var mediaTrack = release.Media.SelectMany(x => x.Tracks).FirstOrDefault(x => x.Id == userRatingForRelease.trackId);
|
||||
if (mediaTrack != null)
|
||||
{
|
||||
var t = track.t.Adapt<TrackList>();
|
||||
t.CssClass = string.IsNullOrEmpty(track.t.Hash) ? "Missing" : "Ok";
|
||||
t.TrackPlayUrl = this.MakeTrackPlayUrl(user, track.t.Id, track.t.RoadieId);
|
||||
var userRating = artistUserTracks.FirstOrDefault(x => x.TrackId == track.t.Id);
|
||||
if (userRating != null)
|
||||
mediaTrack.UserRating = new UserTrack
|
||||
{
|
||||
t.UserRating = new UserTrack
|
||||
{
|
||||
Rating = userRating.Rating,
|
||||
IsFavorite = userRating.IsFavorite ?? false,
|
||||
IsDisliked = userRating.IsDisliked ?? false
|
||||
};
|
||||
}
|
||||
rmTracks.Add(t);
|
||||
Rating = userRatingForRelease.ut.Rating,
|
||||
IsFavorite = userRatingForRelease.ut.IsFavorite ?? false,
|
||||
IsDisliked = userRatingForRelease.ut.IsDisliked ?? false
|
||||
};
|
||||
}
|
||||
rm.Tracks = rmTracks;
|
||||
releaseMedias.Add(rm);
|
||||
}
|
||||
release.Media = releaseMedias.OrderBy(x => x.MediaNumber).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.11" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.13" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -9,6 +9,7 @@ using Roadie.Library.Configuration;
|
|||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Releases;
|
||||
|
@ -598,6 +599,73 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateTrack(User user, Track model)
|
||||
{
|
||||
var didChangeTrack = false;
|
||||
var didChangeThumbnail = false;
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var track = this.DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", model.Id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
track.IsLocked = model.IsLocked;
|
||||
track.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
track.Title = model.Title;
|
||||
track.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
track.Rating = model.Rating;
|
||||
track.AmgId = model.AmgId;
|
||||
track.LastFMId = model.LastFMId;
|
||||
track.MusicBrainzId = model.MusicBrainzId;
|
||||
track.SpotifyId = model.SpotifyId;
|
||||
track.Tags = model.TagsList.ToDelimitedList();
|
||||
track.PartTitles = model.PartTitlesList == null || !model.PartTitlesList.Any() ? null : string.Join("\n", model.PartTitlesList);
|
||||
|
||||
var trackImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (trackImage != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
track.Thumbnail = ImageHelper.ConvertToJpegFormat(trackImage);
|
||||
|
||||
// Save unaltered image to cover file
|
||||
var trackThumbnailName = track.PathToTrackThumbnail(this.Configuration, this.Configuration.LibraryFolder);
|
||||
File.WriteAllBytes(trackThumbnailName, track.Thumbnail);
|
||||
|
||||
// Resize to store in database as thumbnail
|
||||
track.Thumbnail = ImageHelper.ResizeImage(track.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
|
||||
didChangeThumbnail = true;
|
||||
}
|
||||
track.LastUpdated = now;
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.CacheManager.ClearRegion(track.CacheRegion);
|
||||
this.Logger.LogInformation($"UpdateTrack `{ track }` By User `{ user }`: Edited Track [{ didChangeTrack }], Uploaded new image [{ didChangeThumbnail }]");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Fast as possible check if exists and return minimum information on Track
|
||||
/// </summary>
|
||||
|
|
|
@ -47,6 +47,28 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> Update(Track track)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await this.TrackService.UpdateTrack(await this.CurrentUserModel(), track);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc, bool? doRandomize = false)
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt-Core" Version="2.0.0" />
|
||||
<PackageReference Include="Mapster" Version="3.3.2" />
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.0" />
|
||||
<PackageReference Include="Mapster" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OData" Version="7.1.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
|
||||
|
@ -34,7 +34,7 @@
|
|||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFileAlternate" Version="2.0.9" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.11" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.13" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Loading…
Add table
Reference in a new issue