diff --git a/song_of_the_day/Data/DataContext.cs b/song_of_the_day/Data/DataContext.cs index 3a87f7c..0778fd6 100644 --- a/song_of_the_day/Data/DataContext.cs +++ b/song_of_the_day/Data/DataContext.cs @@ -17,5 +17,5 @@ public class DataContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseNpgsql($"Host={AppConfiguration.Instance.DatabaseUri}:{AppConfiguration.Instance.DatabasePort};" + $"Username={AppConfiguration.Instance.DatabaseUser};Password={AppConfiguration.Instance.DatabasePW};" - + $"Database={AppConfiguration.Instance.DatabaseName}"); + + $"Database={AppConfiguration.Instance.DatabaseName}"); } \ No newline at end of file diff --git a/song_of_the_day/Data/User.cs b/song_of_the_day/Data/User.cs index bb00af3..8e1c5a7 100644 --- a/song_of_the_day/Data/User.cs +++ b/song_of_the_day/Data/User.cs @@ -17,7 +17,7 @@ public class User return (string.IsNullOrEmpty(NickName) ? Name : NickName).ToString(); } } - public List LikedSongs { get; set; } + public required List LikedSongs { get; set; } public string? SpotifyAuthAccessToken { get; set; } public int? SpotifyAuthExpiresAfterSeconds { get; set; } diff --git a/song_of_the_day/Pages/Index.cshtml.cs b/song_of_the_day/Pages/Index.cshtml.cs index 1be6614..e3b5da7 100644 --- a/song_of_the_day/Pages/Index.cshtml.cs +++ b/song_of_the_day/Pages/Index.cshtml.cs @@ -21,21 +21,22 @@ public class IndexModel : PageModel public User CurrentUser { - get { - if(_currentUser == null) + get + { + if (_currentUser == null) { var userName = this.User.Identity.Name; - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { _currentUser = dci.Users.Include(u => u.LikedSongs).Where(u => u.LdapUserName == userName).SingleOrDefault(); } } return _currentUser; - } - - } - + } + + } + public bool HasUserLikedThisSong(Song song) { return CurrentUser.LikedSongs.Where(s => s.SongId == song.SongId).FirstOrDefault() != default(Song); @@ -68,7 +69,7 @@ public class IndexModel : PageModel public async Task OnPostUnlikeSong(int? songId) { - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { var user = dci.Users.Include(u => u.LikedSongs).Where(u => u.UserId == CurrentUser.UserId).SingleOrDefault(); var songToRemove = user.LikedSongs.Where(s => s.SongId == songId).SingleOrDefault(); diff --git a/song_of_the_day/Pages/SongSubmission.cshtml.cs b/song_of_the_day/Pages/SongSubmission.cshtml.cs index ddaa8c2..cf9c5b9 100644 --- a/song_of_the_day/Pages/SongSubmission.cshtml.cs +++ b/song_of_the_day/Pages/SongSubmission.cshtml.cs @@ -79,19 +79,20 @@ public class SongSubmissionModel : PageModel public User CurrentUser { - get { - if(_currentUser == null) + get + { + if (_currentUser == null) { var userName = this.User.Identity.Name; - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { _currentUser = dci.Users.Include(u => u.LikedSongs).Where(u => u.LdapUserName == userName).SingleOrDefault(); } } return _currentUser; - } - + } + } public List SpotifySuggestions @@ -262,7 +263,7 @@ public class SongSubmissionModel : PageModel public async Task OnPostUnlikeSong(int? songId) { - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { var user = dci.Users.Include(u => u.LikedSongs).Where(u => u.UserId == CurrentUser.UserId).SingleOrDefault(); var songToRemove = user.LikedSongs.Where(s => s.SongId == songId).SingleOrDefault(); diff --git a/song_of_the_day/Pages/User.cshtml.cs b/song_of_the_day/Pages/User.cshtml.cs index 0523f7b..9031aac 100644 --- a/song_of_the_day/Pages/User.cshtml.cs +++ b/song_of_the_day/Pages/User.cshtml.cs @@ -60,10 +60,10 @@ public class UserModel : PageModel var loginRequest = new LoginRequest( new Uri(spotifyClient.GetLoginRedirectUri()), AppConfiguration.Instance.SpotifyClientId, - LoginRequest.ResponseType.Code) - { - Scope = new[] { Scopes.PlaylistReadPrivate, Scopes.PlaylistReadCollaborative, Scopes.PlaylistModifyPrivate, Scopes.PlaylistModifyPublic, Scopes.UgcImageUpload } - }; + LoginRequest.ResponseType.Code) + { + Scope = new[] { Scopes.PlaylistReadPrivate, Scopes.PlaylistReadCollaborative, Scopes.PlaylistModifyPrivate, Scopes.PlaylistModifyPublic, Scopes.UgcImageUpload } + }; var redirectUri = loginRequest.ToUri().ToString() + $"&finalRedirect={HttpUtility.UrlEncode($"{Request.Scheme}://{Request.Host}:{Request.Host.Port ?? 80}{Request.Path}")}"; return this.Redirect(redirectUri); diff --git a/song_of_the_day/Program.cs b/song_of_the_day/Program.cs index 742da7d..4e0bd7e 100644 --- a/song_of_the_day/Program.cs +++ b/song_of_the_day/Program.cs @@ -291,7 +291,8 @@ app.MapControllerRoute( name: "logout", pattern: "{controller=Auth}/{action=Logout}" ); -app.MapGet("SpotifyLogin", async (HttpRequest request, HttpResponse response) => { +app.MapGet("SpotifyLogin", async (HttpRequest request, HttpResponse response) => +{ var spotifyClient = app.Services.GetService(); var code = request.Query["code"]; var oAuthResponse = await new OAuthClient().RequestToken( diff --git a/song_of_the_day/SongValidators/Base64UrlImageBuilder.cs b/song_of_the_day/SongValidators/Base64UrlImageBuilder.cs index 963bb3d..c313e97 100644 --- a/song_of_the_day/SongValidators/Base64UrlImageBuilder.cs +++ b/song_of_the_day/SongValidators/Base64UrlImageBuilder.cs @@ -15,11 +15,13 @@ public class Base64UrlImageBuilder private string _fileContents = string.Empty; - public string FileContents { - get { + public string FileContents + { + get + { return _fileContents; } - } + } public override string ToString() { diff --git a/song_of_the_day/SongValidators/NavidromeValidator.cs b/song_of_the_day/SongValidators/NavidromeValidator.cs index 77b7db1..e55a9c9 100644 --- a/song_of_the_day/SongValidators/NavidromeValidator.cs +++ b/song_of_the_day/SongValidators/NavidromeValidator.cs @@ -87,31 +87,31 @@ public class NavidromeValidator : SongValidatorBase public class NavidromeShareInfoData { [JsonPropertyName("id")] - public string Id { get; set; } + public required string Id { get; set; } [JsonPropertyName("description")] - public string Description { get; set; } + public required string Description { get; set; } [JsonPropertyName("downloadable")] public bool Downloadable { get; set; } [JsonPropertyName("tracks")] - public List Tracks { get; set; } + public required List Tracks { get; set; } } public class NavidromeTrackInfoData { [JsonPropertyName("id")] - public string Id { get; set; } + public required string Id { get; set; } [JsonPropertyName("title")] - public string Title { get; set; } + public required string Title { get; set; } [JsonPropertyName("artist")] - public string Artist { get; set; } + public required string Artist { get; set; } [JsonPropertyName("album")] - public string Album { get; set; } + public required string Album { get; set; } [JsonPropertyName("updatedAt")] public DateTime UpdatedAt { get; set; } diff --git a/song_of_the_day/SpotifyIntegration/PlayListSynchronizer.cs b/song_of_the_day/SpotifyIntegration/PlayListSynchronizer.cs index 53726fb..7df30bb 100644 --- a/song_of_the_day/SpotifyIntegration/PlayListSynchronizer.cs +++ b/song_of_the_day/SpotifyIntegration/PlayListSynchronizer.cs @@ -43,7 +43,7 @@ public class PlayListSynchronizer public async Task SynchronizePlaylistsAsync(IList playlists) { - foreach(var playlist in playlists) + foreach (var playlist in playlists) { await SynchronizePlaylistAsync(playlist); } @@ -51,7 +51,7 @@ public class PlayListSynchronizer public async Task SynchronizeUserPlaylistsAsync(User user) { - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { var userPlayLists = dci.SmartPlaylistDefinitions .Include(pl => pl.ExplicitlyIncludedSongs) diff --git a/song_of_the_day/SpotifyIntegration/SpotifyApiClient.cs b/song_of_the_day/SpotifyIntegration/SpotifyApiClient.cs index ca7eb40..a05ca8c 100644 --- a/song_of_the_day/SpotifyIntegration/SpotifyApiClient.cs +++ b/song_of_the_day/SpotifyIntegration/SpotifyApiClient.cs @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore; public class SpotifyApiClient { private SpotifyClient _spotifyClient; - private SpotifyClient _userAuthorizedSpotifyClient; + private SpotifyClient? _userAuthorizedSpotifyClient; private ILogger _logger; public SpotifyApiClient(ILogger logger) @@ -25,7 +25,7 @@ public class SpotifyApiClient var refreshResponse = await new OAuthClient().RequestToken( new AuthorizationCodeRefreshRequest( AppConfiguration.Instance.SpotifyClientId, - AppConfiguration.Instance.SpotifyClientSecret, + AppConfiguration.Instance.SpotifyClientSecret, user.SpotifyAuthRefreshToken) ); var config = SpotifyClientConfig @@ -33,7 +33,8 @@ public class SpotifyApiClient .WithAuthenticator(new AuthorizationCodeAuthenticator( AppConfiguration.Instance.SpotifyClientId, AppConfiguration.Instance.SpotifyClientSecret, - new AuthorizationCodeTokenResponse() { + new AuthorizationCodeTokenResponse() + { RefreshToken = refreshResponse.RefreshToken, AccessToken = refreshResponse.AccessToken, TokenType = refreshResponse.TokenType, @@ -46,8 +47,10 @@ public class SpotifyApiClient return this; } - private SpotifyClient UserAuthorizedSpotifyClient { - get { + private SpotifyClient UserAuthorizedSpotifyClient + { + get + { if (_userAuthorizedSpotifyClient == null) { throw new Exception("Cannot perform Spotify API call without user authorization. Authorize Spotify access from your user page first!"); @@ -89,13 +92,13 @@ public class SpotifyApiClient public async Task DeAuthorizeUserAsync(User user) { - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { var isEntityTracked = dci.Entry(user).State != EntityState.Detached; - if(!isEntityTracked) + if (!isEntityTracked) { - user = dci.Users.Find(user.UserId); + user = dci.Users.Find(user.UserId); } user.SpotifyAuthAccessToken = string.Empty; user.SpotifyAuthRefreshToken = string.Empty; @@ -107,13 +110,13 @@ public class SpotifyApiClient public async Task GetValidAuthorizationTokenAsync(User user) { - if(string.IsNullOrEmpty(user.SpotifyAuthAccessToken)) + if (string.IsNullOrEmpty(user.SpotifyAuthAccessToken)) { // user either never connected Spotify or we failed to refresh token - user needs to re-authenticate return string.Empty; } - if(!this.IsAuthTokenExpired(user)) + if (!this.IsAuthTokenExpired(user)) { return user.SpotifyAuthAccessToken; } @@ -123,12 +126,12 @@ public class SpotifyApiClient var isEntityTracked = dci.Entry(user).State != EntityState.Detached; - if(!isEntityTracked) + if (!isEntityTracked) { - user = dci.Users.Find(user.UserId); + user = dci.Users.Find(user.UserId); } - try + try { var oAuthResponse = await new OAuthClient().RequestToken( new AuthorizationCodeRefreshRequest(AppConfiguration.Instance.SpotifyClientId, AppConfiguration.Instance.SpotifyClientSecret, user.SpotifyAuthRefreshToken) @@ -139,7 +142,7 @@ public class SpotifyApiClient user.SpotifyAuthRefreshToken = oAuthResponse.RefreshToken; return user.SpotifyAuthAccessToken; } - catch(Exception ex) + catch (Exception ex) { _logger.LogWarning($"Failed to refresh SpotifyAuth token for user {user.LdapUserName}: {ex.Message}"); await DeAuthorizeUserAsync(user); @@ -186,7 +189,7 @@ public class SpotifyApiClient var playlist = await UserAuthorizedSpotifyClient.Playlists.Create(currentUser.Id, playlistCreationRequest); _logger.LogWarning($"Creating new playlist '{playlistTitle}'"); - using(var dci = DataContext.Instance) + using (var dci = DataContext.Instance) { var trackedUserEntity = dci.Users.Find(createdBy.UserId); var newPlaylist = new SmartPlaylistDefinition() @@ -240,18 +243,18 @@ public class SpotifyApiClient return string.Empty; } try - { - // for now hardcoded with my user ID - var addItemRequest = new PlaylistAddItemsRequest(songIds.Select(id => $"spotify:track:{id}").ToList()); - _logger.LogWarning($"Adding songs to playlist with id '{playlistId}'"); - var response = await UserAuthorizedSpotifyClient.Playlists.AddItems(playlistId, addItemRequest); - return response.SnapshotId; + { + // for now hardcoded with my user ID + var addItemRequest = new PlaylistAddItemsRequest(songIds.Select(id => $"spotify:track:{id}").ToList()); + _logger.LogWarning($"Adding songs to playlist with id '{playlistId}'"); + var response = await UserAuthorizedSpotifyClient.Playlists.AddItems(playlistId, addItemRequest); + return response.SnapshotId; - } - catch (APIException ex) - { - throw new Exception($"Error adding songs to playlist with id: {playlistId}: {ex.Message}", ex); - } + } + catch (APIException ex) + { + throw new Exception($"Error adding songs to playlist with id: {playlistId}: {ex.Message}", ex); + } } public async Task RemoveSongsFromPlaylist(string playlistId, List songIds) @@ -274,7 +277,7 @@ public class SpotifyApiClient }; removeItemsRequest.Tracks.Add(item); } - + _logger.LogWarning($"Removing songs from playlist with id '{playlistId}'"); var response = await UserAuthorizedSpotifyClient.Playlists.RemoveItems(playlistId, removeItemsRequest); return response.SnapshotId;