diff --git a/Mixonomer.xcodeproj/project.pbxproj b/Mixonomer.xcodeproj/project.pbxproj index b3adbfb..74866df 100644 --- a/Mixonomer.xcodeproj/project.pbxproj +++ b/Mixonomer.xcodeproj/project.pbxproj @@ -9,6 +9,9 @@ /* Begin PBXBuildFile section */ A10C8D29281302050018AE12 /* ToastUI in Frameworks */ = {isa = PBXBuildFile; productRef = A10C8D28281302050018AE12 /* ToastUI */; }; A11AC70628A188AE00645043 /* AuthApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11AC70528A188AE00645043 /* AuthApi.swift */; }; + A1AF726F28A84F7D00D317C9 /* AdminApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF726E28A84F7D00D317C9 /* AdminApi.swift */; }; + A1AF727128A850AE00D317C9 /* UsersList.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF727028A850AE00D317C9 /* UsersList.swift */; }; + A1AF727328A9062600D317C9 /* UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1AF727228A9062600D317C9 /* UserView.swift */; }; A1DBCDA628A51869002CF730 /* AdminList.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1DBCDA528A51869002CF730 /* AdminList.swift */; }; E906F7F42414019C004E1E31 /* NetworkPersister.swift in Sources */ = {isa = PBXBuildFile; fileRef = E906F7F32414019C004E1E31 /* NetworkPersister.swift */; }; E906F7F724143AA7004E1E31 /* SwiftUICharts in Frameworks */ = {isa = PBXBuildFile; productRef = E906F7F624143AA7004E1E31 /* SwiftUICharts */; }; @@ -66,6 +69,9 @@ /* Begin PBXFileReference section */ A11AC70528A188AE00645043 /* AuthApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthApi.swift; sourceTree = ""; }; A146915A28118F940052999D /* Mixonomer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Mixonomer.entitlements; sourceTree = ""; }; + A1AF726E28A84F7D00D317C9 /* AdminApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminApi.swift; sourceTree = ""; }; + A1AF727028A850AE00D317C9 /* UsersList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersList.swift; sourceTree = ""; }; + A1AF727228A9062600D317C9 /* UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserView.swift; sourceTree = ""; }; A1DBCDA528A51869002CF730 /* AdminList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminList.swift; sourceTree = ""; }; E906F7F32414019C004E1E31 /* NetworkPersister.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkPersister.swift; sourceTree = ""; }; E934AC98240DD0E4009869F4 /* AddTagSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTagSheet.swift; sourceTree = ""; }; @@ -139,6 +145,8 @@ isa = PBXGroup; children = ( A1DBCDA528A51869002CF730 /* AdminList.swift */, + A1AF727028A850AE00D317C9 /* UsersList.swift */, + A1AF727228A9062600D317C9 /* UserView.swift */, ); path = Admin; sourceTree = ""; @@ -163,6 +171,7 @@ E9E30C2523FEA4EF00574EEF /* TagApi.swift */, E906F7F32414019C004E1E31 /* NetworkPersister.swift */, A11AC70528A188AE00645043 /* AuthApi.swift */, + A1AF726E28A84F7D00D317C9 /* AdminApi.swift */, ); path = Network; sourceTree = ""; @@ -436,6 +445,7 @@ E98254CA23FA26600056D9D3 /* PlaylistRow.swift in Sources */, E9EA690B23F9A5430012C3E8 /* AppDelegate.swift in Sources */, E906F7F42414019C004E1E31 /* NetworkPersister.swift in Sources */, + A1AF727328A9062600D317C9 /* UserView.swift in Sources */, E9E30C3323FF255C00574EEF /* SettingsList.swift in Sources */, E9EA690D23F9A5430012C3E8 /* SceneDelegate.swift in Sources */, E98254DB23FB64740056D9D3 /* Network.swift in Sources */, @@ -445,6 +455,8 @@ A1DBCDA628A51869002CF730 /* AdminList.swift in Sources */, E97AF46023FC85D600635494 /* PlaylistApi.swift in Sources */, A11AC70628A188AE00645043 /* AuthApi.swift in Sources */, + A1AF726F28A84F7D00D317C9 /* AdminApi.swift in Sources */, + A1AF727128A850AE00D317C9 /* UsersList.swift in Sources */, E9EA690F23F9A5430012C3E8 /* AppSkeleton.swift in Sources */, E98254BD23F9B7A90056D9D3 /* Playlist.swift in Sources */, E97AF46723FD650800635494 /* AddPlaylistSheet.swift in Sources */, diff --git a/Mixonomer/Model/User.swift b/Mixonomer/Model/User.swift index 4c890e9..2fe6b41 100644 --- a/Mixonomer/Model/User.swift +++ b/Mixonomer/Model/User.swift @@ -69,16 +69,23 @@ class User: Identifiable, Decodable { email = try container.decode(String.self, forKey: .email) }catch { email = nil - debugPrint("failed to parse email") } type = try container.decode(UserType.self, forKey: .type) last_login = try container.decode(String.self, forKey: .last_login) - last_keygen = try container.decode(String.self, forKey: .last_keygen) + do{ + last_keygen = try container.decode(String.self, forKey: .last_keygen) + }catch { + last_keygen = "" + } spotify_linked = try container.decode(Bool.self, forKey: .spotify_linked) - lastfm_username = try container.decode(String.self, forKey: .lastfm_username) + do{ + lastfm_username = try container.decode(String.self, forKey: .lastfm_username) + }catch { + lastfm_username = nil + } } func encode(to encoder: Encoder) throws { diff --git a/Mixonomer/Network/AdminApi.swift b/Mixonomer/Network/AdminApi.swift new file mode 100644 index 0000000..2fc92c0 --- /dev/null +++ b/Mixonomer/Network/AdminApi.swift @@ -0,0 +1,53 @@ +// +// AdminApi.swift +// Mixonomer +// +// Created by Andy Pack on 13/08/2022. +// Copyright © 2022 Sarsoo. All rights reserved. +// + +import Foundation +import Alamofire +import SwiftyJSON + +public enum AdminApi { + case getUsers +} + +extension AdminApi: ApiRequest { + var domain: String { + return ApiRequestDefaults.domain + } + + var path: String { + switch self { + case .getUsers: + return "api/users" + } + } + + var httpMethod: HTTPMethod { + switch self { + case .getUsers: + return .get + } + } + + var parameters: JSON? { + nil + } + + var parameterType: ParameterEncoder? { + nil + } + + var headers: HTTPHeaders? { + nil + } + + var authMethod: AuthMethod? { + return ApiRequestDefaults.authMethod + } + + +} diff --git a/Mixonomer/Views/Admin/AdminList.swift b/Mixonomer/Views/Admin/AdminList.swift index 064b9be..8376774 100644 --- a/Mixonomer/Views/Admin/AdminList.swift +++ b/Mixonomer/Views/Admin/AdminList.swift @@ -12,8 +12,12 @@ struct AdminList: View { var body: some View { NavigationView { List{ - Section { - + Section(header: Text("Users")) { + NavigationLink(destination: UsersList()) { + HStack { + Text("View Users") + } + } } } .listStyle(GroupedListStyle()) diff --git a/Mixonomer/Views/Admin/UserView.swift b/Mixonomer/Views/Admin/UserView.swift new file mode 100644 index 0000000..e4d9419 --- /dev/null +++ b/Mixonomer/Views/Admin/UserView.swift @@ -0,0 +1,68 @@ +// +// UserView.swift +// Mixonomer +// +// Created by Andy Pack on 14/08/2022. +// Copyright © 2022 Sarsoo. All rights reserved. +// + +import SwiftUI + +struct UserView: View { + + @EnvironmentObject var liveUser: LiveUser + @Binding var user: User + + var body: some View { + Form { + + Section { + HStack { + Text("Type") + Spacer() + Text(user.type.rawValue) + .foregroundColor(.gray) + } + } + + Section(header: Text("External")) { + HStack { + Text("Spotify") + Spacer() + Text(user.spotify_linked ? "✅" : "❌") + .foregroundColor(.gray) + } + + HStack { + Text("Last.fm") + Spacer() + Text(user.lastfm_username ?? "") + .foregroundColor(.gray) + } + } + + Section(header: Text("Timestamps")) { + HStack { + Text("Last Web Login") + Spacer() + Text(user.last_login) + .foregroundColor(.gray) + } + + HStack { + Text("Last Keygen") + Spacer() + Text(user.last_keygen) + .foregroundColor(.gray) + } + } + } + .navigationBarTitle(Text(user.username)) + } +} + +struct UserView_Previews: PreviewProvider { + static var previews: some View { + UserView(user: .constant(User(username: "", email: "", last_login: "", last_keygen: "", spotify_linked: true, lastfm_username: nil))) + } +} diff --git a/Mixonomer/Views/Admin/UsersList.swift b/Mixonomer/Views/Admin/UsersList.swift new file mode 100644 index 0000000..3e3861e --- /dev/null +++ b/Mixonomer/Views/Admin/UsersList.swift @@ -0,0 +1,76 @@ +// +// UsersList.swift +// Mixonomer +// +// Created by Andy Pack on 13/08/2022. +// Copyright © 2022 Sarsoo. All rights reserved. +// + +import SwiftUI +import SwiftyJSON + +struct UsersList: View { + + @EnvironmentObject var liveUser: LiveUser + + @State private var users: [User] = [] + + var body: some View { + List{ + Section { // Weird? added empty header as list renders with space for header then jumps up, not nice + if self.users.count > 0 { + ForEach(self.users.indices, id: \.self){ userIdx in + + NavigationLink(destination: UserView(user: self.$users[userIdx])) { + Text(self.users[userIdx].username) + } + } + }else { + HStack { + Text("No Users") + .multilineTextAlignment(.center) + Spacer() + } + } + } + } +// .id(UUID()) + .navigationBarTitle("Users") + .onAppear { + self.get_users() + } + } + + func get_users() { + let api = AdminApi.getUsers + RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in + + if self.liveUser.check_network_response(response: response) { + + guard let data = response.data else { + fatalError("error getting users") + } + + guard let json = try? JSON(data: data) else { + fatalError("error parsing user") + } + + // update state + self.users = UserApi.fromJSON(user: json["accounts"].arrayValue) + .sorted(by: { (user1, user2) in + return user1.username < user2.username + }) + + } else { + + } + } + } +} + +struct UsersList_Previews: PreviewProvider { + static var previews: some View { + UsersList() + .environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false)) + } +} diff --git a/Mixonomer/Views/AppSkeleton.swift b/Mixonomer/Views/AppSkeleton.swift index 6c95c3c..9da79c4 100644 --- a/Mixonomer/Views/AppSkeleton.swift +++ b/Mixonomer/Views/AppSkeleton.swift @@ -28,17 +28,16 @@ struct AppSkeleton: View { } .tag(0) - if let user = liveUser.user { - if let _ = user.lastfm_username { - TagList() - .tabItem { - VStack { - Image(systemName: "tag") - Text("Tags") - } + if liveUser.lastfm_connected() { + + TagList() + .tabItem { + VStack { + Image(systemName: "tag") + Text("Tags") } - .tag(1) - } + } + .tag(1) } if let user = liveUser.user { diff --git a/Mixonomer/Views/Playlist/PlaylistView.swift b/Mixonomer/Views/Playlist/PlaylistView.swift index 240cb78..49672a4 100644 --- a/Mixonomer/Views/Playlist/PlaylistView.swift +++ b/Mixonomer/Views/Playlist/PlaylistView.swift @@ -329,15 +329,26 @@ struct PlaylistView: View { struct PlaylistView_Previews: PreviewProvider { static var previews: some View { - PlaylistView(playlist: .constant( - Playlist(name: "playlist name", - username: "username", - lastfm_stat_percent: 30, - lastfm_stat_album_percent: 40, - lastfm_stat_artist_percent: 80 - ) - )) - .environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false)) + Group { + PlaylistView(playlist: .constant( + Playlist(name: "playlist name", + username: "username", + lastfm_stat_percent: 30, + lastfm_stat_album_percent: 40, + lastfm_stat_artist_percent: 80 + ) + )) + .environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false)) + PlaylistView(playlist: .constant( + Playlist(name: "playlist name", + username: "username", + lastfm_stat_percent: 30, + lastfm_stat_album_percent: 40, + lastfm_stat_artist_percent: 80 + ) + )) + .environmentObject(LiveUser(playlists: [], tags: [], username: "user", loggedIn: false, user: User(username: "", email: "", last_login: "", last_keygen: "", spotify_linked: true, lastfm_username: "last.fm"))) + } } }