using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Nancy; using Nancy.ModelBinding; using Sony.Filtr.AdminAPI.Config; using Sony.Filtr.AdminAPI.Utility; using Sony.Filtr.Applications; using Sony.Filtr.Buzz; using Sony.Filtr.Contracts.Definitions; using Sony.Filtr.Contracts.Entities; using Sony.Filtr.Contracts.Entities.Buzz; using Sony.Filtr.Contracts.ViewModels; using Sony.Filtr.Core.EditorialPlaylists; using Sony.Filtr.Core.SpotifyUserFollowers; using Sony.Filtr.SpotifyWebAPI; using Sony.Filtr.DeezerAPI; using Sony.Filtr.Playlists.Deezer; using Sony.Filtr.Utility.Extensions; namespace Sony.Filtr.AdminAPI.Modules.Buzz { public class BuzzUserAccountModule : BaseModule { private readonly SpotifyWebApi _spotifyWebApi; private readonly DeezerApi _deezerApi; private readonly SpotifyUserFollowersManager _spotifyUserFollowersManager; private readonly EditorialPlaylistStatsManager _editorialPlaylistStatsManager; private readonly DeezerFanLogManager _deezerFanLogManager; public BuzzUserAccountModule(ApplicationInstanceManager applicationInstanceManager, BuzzAccountManager buzzAccountManager, SpotifyWebApi spotifyWebApi, DeezerApi deezerApi, SpotifyUserFollowersManager spotifyUserFollowersManager, EditorialPlaylistStatsManager editorialPlaylistStatsManager, DeezerFanLogManager deezerFanLogManager) : base(applicationInstanceManager) { _spotifyWebApi = spotifyWebApi; _deezerApi = deezerApi; _spotifyUserFollowersManager = spotifyUserFollowersManager; _editorialPlaylistStatsManager = editorialPlaylistStatsManager; _deezerFanLogManager = deezerFanLogManager; Get["/New/BuzzUsers/Categories"] = parameters => { var buzzCategories = buzzAccountManager.GetBuzzCategories(); return Response.AsJson(buzzCategories); }; Get["BuzzUserAccountListCategories", "/BuzzUserAccount/Categories"] = parameters => { var buzzCategories = buzzAccountManager.GetBuzzCategories(); return Response.AsJson(buzzCategories); }; //Get["BuzzUserAccountListGroups", "/BuzzUserAccount/Groups"] = parameters => //{ // var groupIdstring = (string)Request.Query.groupId; // if (string.IsNullOrWhiteSpace(groupIdstring)) // return HttpStatusCode.BadRequest; // var groupIds = groupIdstring.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(p=> int.Parse(p)).ToList(); // if (!groupIds.Any()) // return HttpStatusCode.BadRequest; // var buzzGroups = buzzAccountManager.GetBuzzGroups(groupIds); // var viewModels = GetBuzzGroupAggregateViewModels(spotifyPlaylistManager, buzzGroups); // return Response.AsJson(viewModels); //}; //Get["BuzzUserAccountGroupsInCategory", "/BuzzUserAccount/Categories/{categoryId}/Groups"] = parameters => //{ // var buzzCategory = GetBuzzCategoryFromPath((string)parameters.categoryId); // var buzzGroups = buzzAccountManager.GetBuzzGroups(buzzCategory); // var viewModels = GetBuzzGroupAggregateViewModels(spotifyPlaylistManager, buzzGroups); // return Response.AsJson(viewModels); //}; //Post["BuzzUserAccountAddGroup", "/BuzzUserAccount/Categories/{categoryId}/Groups"] = parameters => //{ // var buzzCategory = GetBuzzCategoryFromPath((string)parameters.categoryId); // BuzzGroupAddRequest buzzGroupAddRequest = this.Bind(); // if (buzzGroupAddRequest == null || string.IsNullOrWhiteSpace(buzzGroupAddRequest.Name)) // return HttpStatusCode.BadRequest; // var addedBuzzGroup = buzzAccountManager.AddGroup(new BuzzGroup() // { // BuzzCategoryId = buzzCategory.ID, // Name = buzzGroupAddRequest.Name // }); // return Response.AsJson(addedBuzzGroup); //}; //Get["BuzzUserAccountGroupUserMapping", "/BuzzUserAccount/Categories/{categoryId}/GroupUserMapping"] = parameters => //{ // var buzzCategory = GetBuzzCategoryFromPath((string)parameters.categoryId); // var groupUserMapping = buzzAccountManager.GetBuzzUserGroupMapping(buzzCategory); // return Response.AsJson(groupUserMapping); //}; Get["BuzzUserAccountGetUsers", "/BuzzUserAccount/users", true] = async (parameters, cx) => { var musicServiceId = (int?)Request.Query.musicServiceId; string buzzCategoryIdParameter = (string)Request.Query.buzzCategoryId; var limit = (int?)Request.Query.limit ?? 100; var offset = (int?)Request.Query.offset ?? 0; // Uncategorized users List buzzUsers = new List(); if (buzzCategoryIdParameter != null && buzzCategoryIdParameter.Equals("null", StringComparison.InvariantCultureIgnoreCase)) { buzzUsers = await buzzAccountManager.GetUncategorizedBuzzUsersAsync(musicServiceId: musicServiceId); return Response.AsJson(buzzUsers); } List buzzCategoryIds = new List(); if (buzzCategoryIdParameter != null) { buzzCategoryIds = buzzCategoryIdParameter.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(id => int.Parse(id)).ToList(); } // Users in category if (buzzCategoryIds.Any()) { foreach (var buzzCategoryId in buzzCategoryIds) { var users = await buzzAccountManager.GetBuzzUsersAsync(buzzCategoryId, musicServiceId); buzzUsers.AddRange(users); } } else // All users { var users = await buzzAccountManager.GetBuzzUsersAsync(musicServiceId: musicServiceId); buzzUsers.AddRange(users); } var viewModel = buzzUsers.Select(b=> BuildBuzzUserViewModel(b)).ToList().Paginate(limit, offset); return Response.AsJson(viewModel); }; Get["BuzzUserAccountGetUser", "/BuzzUserAccount/users/{userId}", true] = async (parameters, cx) => { var buzzUserId = (int?)parameters.userId; if (!buzzUserId.HasValue) return HttpStatusCode.BadRequest; var existingBuzzUser = await buzzAccountManager.GetBuzzUserAsync(buzzUserId.Value); if (existingBuzzUser == null) return HttpStatusCode.NotFound; var viewModel = BuildBuzzUserViewModel(existingBuzzUser); return Response.AsJson(viewModel); }; Get["BuzzUserAccountGetUserHistory", "/BuzzUserAccount/users/{userId}/history", true] = async (parameters, cx) => { var buzzUserId = (int?)parameters.userId; if (!buzzUserId.HasValue) return HttpStatusCode.BadRequest; var existingBuzzUser = await buzzAccountManager.GetBuzzUserAsync(buzzUserId.Value); if (existingBuzzUser == null) return HttpStatusCode.NotFound; DateTime? startDate; DateTime? endDate; ParseDates(out startDate, out endDate); if (existingBuzzUser.MusicServiceId == (int)MusicService.Spotify) { var exportViewModel = await GetSpotifyBuzzUserAccountHistoryExport(existingBuzzUser, startDate, endDate); return Response.AsJson(exportViewModel); } else if (existingBuzzUser.MusicServiceId == (int)MusicService.Deezer) { var exportViewModel = await GetDeezerBuzzUserAccountHistoryExport(existingBuzzUser, startDate, endDate); return Response.AsJson(exportViewModel); } var viewModel = BuildBuzzUserViewModel(existingBuzzUser); return Response.AsJson(viewModel); }; Post["BuzzUserAccountAddUser", "/BuzzUserAccount/users", true] = async (parameters,cx) => { BuzzUserPostObject buzzUserPostObject = this.Bind(); if (buzzUserPostObject == null || string.IsNullOrWhiteSpace(buzzUserPostObject.Username)) return HttpStatusCode.BadRequest; var musicServiceId = buzzUserPostObject.MusicServiceId; if (musicServiceId == null) return HttpStatusCode.BadRequest; var existingBuzzUser = await buzzAccountManager.GetBuzzUserAsync(buzzUserPostObject.Username, (int)musicServiceId); if (existingBuzzUser != null) return HttpStatusCode.Conflict; var buzzUser = new BuzzUser() { Username = buzzUserPostObject.Username, BuzzCategoryId = buzzUserPostObject.BuzzCategoryId, CountryCode = buzzUserPostObject.CountryCode?.ToLowerInvariant(), MusicServiceId = musicServiceId.Value, ImportPlaylists = buzzUserPostObject.ImportPlaylists ?? true, Tags = buzzUserPostObject.Tags, }; buzzUser = await VerifyAccountAsync(buzzUser); var addedBuzzUser = await buzzAccountManager.AddBuzzUserAsync(buzzUser); var viewModel = BuildBuzzUserViewModel(addedBuzzUser); return Response.AsJson(viewModel); }; Put["BuzzUserAccountUpdateUser", "/BuzzUserAccount/users/{userId}", true] = async (parameters, cx) => { BuzzUserPostObject buzzUser = this.Bind(); if (buzzUser == null || string.IsNullOrWhiteSpace(buzzUser.Username)) return HttpStatusCode.BadRequest; var buzzUserId = (int?)parameters.userId; if (!buzzUserId.HasValue) return HttpStatusCode.BadRequest; var existingBuzzUser = await buzzAccountManager.GetBuzzUserAsync(buzzUserId.Value); if (existingBuzzUser == null) return HttpStatusCode.NotFound; var musicServiceId = buzzUser.MusicServiceId; if (musicServiceId == null) return HttpStatusCode.BadRequest; if (existingBuzzUser.Username != buzzUser.Username) { //Updating username, verify that new name doesn't already exist. var existingBuzzUserWithNewUsername = await buzzAccountManager.GetBuzzUserAsync(buzzUser.Username, musicServiceId.Value); if (existingBuzzUserWithNewUsername != null) return HttpStatusCode.Conflict; } existingBuzzUser.Username = buzzUser.Username; existingBuzzUser.BuzzCategoryId = buzzUser.BuzzCategoryId; existingBuzzUser.CountryCode = buzzUser.CountryCode?.ToLowerInvariant(); existingBuzzUser.MusicServiceId = musicServiceId.Value; existingBuzzUser.ImportPlaylists = buzzUser.ImportPlaylists ?? true; existingBuzzUser.Tags = buzzUser.Tags; existingBuzzUser = await VerifyAccountAsync(existingBuzzUser); var addedBuzzUser = await buzzAccountManager.UpdateBuzzUserAsync(existingBuzzUser); var viewModel = BuildBuzzUserViewModel(addedBuzzUser); return Response.AsJson(viewModel); }; Delete["BuzzUserAccountDeleteUser", "/BuzzUserAccount/users/{userId}", true] = async (parameters, cx) => { var buzzUserId = (int?) parameters.userId; if (!buzzUserId.HasValue) return HttpStatusCode.BadRequest; var existingBuzzUser = await buzzAccountManager.GetBuzzUserAsync(buzzUserId.Value); if (existingBuzzUser == null) return HttpStatusCode.NotFound; await buzzAccountManager.DeleteBuzzUserAsync(existingBuzzUser); return HttpStatusCode.Accepted; }; //Post["BuzzUserAccountAddUserToGroup", "/BuzzUserAccount/Groups/{groupId}/users", true] = async (parameters, cx) => // { // int groupId = parameters.groupId; // var buzzGroup = buzzAccountManager.GetBuzzGroup(groupId); // if (buzzGroup == null) // return HttpStatusCode.NotFound; // BuzzUserAddToGroupRequest buzzUserAddToGroupRequest = this.Bind(); // if (buzzUserAddToGroupRequest == null || buzzUserAddToGroupRequest.BuzzUserID == default(int)) // return HttpStatusCode.BadRequest; // var existingBuzzUser = await buzzAccountManager.GetBuzzUserAsync(buzzUserAddToGroupRequest.BuzzUserID); // if (existingBuzzUser == null) // return HttpStatusCode.BadRequest; // buzzAccountManager.AddBuzzUserToGroup(existingBuzzUser, buzzGroup); // return HttpStatusCode.OK; //TODO: Response? // }; // Get["BuzzUserAccountGetPlaylistForGroup", "/BuzzUserAccount/Groups/{groupId}/Playlists", true] = async (parameters, cx) => // { // int groupId = parameters.groupId; // var buzzGroup = buzzAccountManager.GetBuzzGroup(groupId); // if (buzzGroup == null) // return HttpStatusCode.NotFound; // var playlists = spotifyPlaylistManager.GetPlaylistsForBuzzGroup(groupId); // var attributes = await editorialPlaylistManager.GetPlaylistAttributesAsync(playlists.Select(p => p.PlaylistUri)); // var playlistsViewModels = playlists.Select(p => BuildPlaylistViewModel(p, attributes)).ToList(); // return Response.AsJson(new BuzzPlaylistResponse() // { // Playlists = playlistsViewModels // }); // }; // Get["BuzzUserAccountGetPlaylistForCategory", "/BuzzUserAccount/Categories/{categoryId}/Playlists", true] = async (parameters, cx) => // { // var buzzCategory = GetBuzzCategoryFromPath((string)parameters.categoryId); // var playlists = spotifyPlaylistManager.GetPlaylistsForBuzzCategoryId(buzzCategory); // var attributes = await editorialPlaylistManager.GetPlaylistAttributesAsync(playlists.Select(p => p.PlaylistUri)); // var playlistsViewModels = playlists.Select(p => BuildPlaylistViewModel(p, attributes)).ToList(); // return Response.AsJson(new BuzzPlaylistResponse() // { // Playlists = playlistsViewModels // }); // }; } private BuzzUserViewModel BuildBuzzUserViewModel(BuzzUser buzzUser) { var viewModel = AutoMapper.Mapper.Map(buzzUser); viewModel.ImageUrl = ImageUrlUtility.GetAbsoluteImageUrl(buzzUser.Image); return viewModel; } private async Task GetDeezerBuzzUserAccountHistoryExport(BuzzUser buzzUser, DateTime? startDate, DateTime? endDate) { var deezerUserId = int.Parse(buzzUser.Username); var playlistStats = await _deezerFanLogManager.GetDeezerPlaylistFansStatsForUserAsync(deezerUserId); var summedPlaylistStats = playlistStats.GroupBy(g => g.Date).Select(d => new { Date = d.Key, PlaylistSubscribers = d.Sum(di=> di.Fans) }); var userFans = await _deezerFanLogManager.GetDeezerUserFansStatsAsync(deezerUserId); var items = userFans.Join(summedPlaylistStats, userStat => userStat.Date.Date, playlistStat => playlistStat.Date.Date, (userStat, playlistStat) => new BuzzUserAccountHistoryExportValue() { Timestamp = userStat.Date, Subscribers = userStat.Fans, PlaylistSubscribers = playlistStat.PlaylistSubscribers, } ).ToList(); items = items.FilterByDate(startDate, endDate).ToList(); return new BuzzUserAccountHistoryExport() { BuzzUser = buzzUser, Items = items, Filtering = new DateFiltering() { StartDate = startDate, EndDate = endDate} }; } private async Task GetSpotifyBuzzUserAccountHistoryExport(BuzzUser buzzUser, DateTime? startDate, DateTime? endDate) { var username = SpotifyLink.ParseUserLink(buzzUser.Username).ExtractSpotifyUserName(); var userFollowers = await _spotifyUserFollowersManager.GetFollowerDataAsync(username, startDate, endDate); var playlistStats = await _editorialPlaylistStatsManager.GetCombinedPlaylistStatsAsync(username); var items = userFollowers.Join(playlistStats, stat => stat.Date.Date, pair => pair.Date.Date, (stat, pairs) => new BuzzUserAccountHistoryExportValue() { Timestamp = pairs.Timestamp, Subscribers = stat.Followers, PlaylistSubscribers = pairs.Subscribers, } ).ToList(); items = items.FilterByDate(startDate, endDate).ToList(); var exportViewModel = new BuzzUserAccountHistoryExport() { BuzzUser = buzzUser, Filtering = new DateFiltering() { StartDate = startDate, EndDate = endDate }, Items = items, }; return exportViewModel; } private void ParseDates(out DateTime? startDate, out DateTime? endDate) { DateTime tempStartDate; if (DateTime.TryParse((string)Request.Query.startDate, out tempStartDate)) { startDate = tempStartDate; } else { startDate = null; } DateTime tempEndDate; if (DateTime.TryParse((string)Request.Query.endDate, out tempEndDate)) { endDate = tempEndDate; } else { endDate = null; } } private async Task VerifyAccountAsync(BuzzUser buzzUser) { if (buzzUser.MusicServiceId == (int)MusicService.Spotify) { try { var user = await _spotifyWebApi.GetUserAsync(buzzUser.Username); buzzUser.DisplayName = user.display_name; } catch (Exception) { throw new NancyStatusException(HttpStatusCode.BadRequest, "Invalid user for service"); } } else if (buzzUser.MusicServiceId == (int)MusicService.Deezer) { try { int deezerUserId = int.Parse(buzzUser.Username); var response = await _deezerApi.GetUserAsync(deezerUserId); buzzUser.DisplayName = response.name; } catch (Exception) { throw new NancyStatusException(HttpStatusCode.BadRequest, "Invalid user for service"); } } return buzzUser; } //private BuzzCategory GetBuzzCategoryFromPath(string categoryIdParameter) //{ // int categoryId; // BuzzCategory buzzCategory = null; // if (int.TryParse(categoryIdParameter, out categoryId)) // { // buzzCategory = _buzzAccountManager.GetBuzzCategory(categoryId); // } // if (buzzCategory == null) // throw new NancyStatusException(HttpStatusCode.NotFound, "Could not find specified buzz category id"); // return buzzCategory; //} //private static List GetBuzzGroupAggregateViewModels(SpotifyPlaylistManager spotifyPlaylistManager, List buzzGroups) //{ // List viewModels = new List(); // foreach (var buzzGroup in buzzGroups) // { // var playlists = spotifyPlaylistManager.GetPlaylistsForBuzzGroup(buzzGroup.ID); // viewModels.Add(new BuzzGroupAggregateViewModel() // { // GroupId = buzzGroup.ID, // GroupName = buzzGroup.Name, // NumPlaylists = playlists.Count, // TotalPlaylistFollowers = playlists.Sum(p => p.Followers), // AccountFollowers = 0, // AccountFollowersDailyChange = 0, // PlaylistFollowersDailyChange = 0, // PlaylistFollowersDailyChange30 = 0 // }); // } // return viewModels; //} //private SpotifyPlaylistViewModel BuildPlaylistViewModel(SpotifyPlaylist spotifyPlaylist, Dictionary attributes) //{ // var viewModel = AutoMapper.Mapper.Map(spotifyPlaylist); // EditorialPlaylistAttributes attribute; // attributes.TryGetValue(spotifyPlaylist.PlaylistUri, out attribute); // if (attribute != null) // viewModel.Followers = attribute.Followers; // return viewModel; //} //public class SpotifyPlaylistViewModel : SpotifyPlaylist //{ // public long? Followers { get; set; } //} //public class BuzzPlaylistResponse //{ // public List Playlists { get; set; } // public List BuzzGroupUserMappings { get; set; } //} //public class BuzzGroupAddRequest //{ // public string Name { get; set; } //} public class BuzzUserPostObject { public string Username { get; set; } public string CountryCode { get; set; } public int? MusicServiceId { get; set; } public int? BuzzCategoryId { get; set; } public bool? ImportPlaylists { get; set; } public List Tags { get; set; } } //public class BuzzUserAddToGroupRequest //{ // public int BuzzUserID { get; set; } //} //public class BuzzGroupAggregateViewModel //{ // public string GroupName { get; set; } // public int GroupId { get; set; } // public int NumPlaylists { get; set; } // public long TotalPlaylistFollowers { get; set; } // public int PlaylistFollowersDailyChange { get; set; } // public int PlaylistFollowersDailyChange30 { get; set; } // public int AccountFollowers { get; set; } // public int AccountFollowersDailyChange { get; set; } //} public class BuzzUserAccountHistoryExport : StatisticsExportViewModel { public BuzzUser BuzzUser { get; set; } } public class BuzzUserAccountHistoryExportValue : StatisticValue { public int Subscribers { get; set; } public long PlaylistSubscribers { get; set; } } public class BuzzUserViewModel { public int ID { get; set; } public string Username { get; set; } public string DisplayName { get; set; } public int? BuzzCategoryId { get; set; } public int MusicServiceId { get; set; } public string CountryCode { get; set; } public bool ImportPlaylists { get; set; } public int? Subscribers { get; set; } public long? PlaylistSubscribers { get; set; } public string ImageUrl { get; set; } public bool Error { get; set; } public List Tags { get; set; } public List BuzzGroups { get; set; } } } }