mirror of
https://github.com/idanoo/GoScrobble.git
synced 2024-11-22 08:25:14 +00:00
0.0.12
- Add client TZ support + Selectable on user page - Move token auth to GET ?key=XYZ for wider webhook support - Add Multiscrobbler support - Add /api/v1/serverinfo for version information
This commit is contained in:
parent
9866dea36b
commit
67e43b8984
@ -1,3 +1,9 @@
|
|||||||
|
# 0.0.12
|
||||||
|
- Add client TZ support + Selectable on user page
|
||||||
|
- Move token auth to GET ?key=XYZ for wider webhook support
|
||||||
|
- Add Multiscrobbler support
|
||||||
|
- Add /api/v1/serverinfo for version information
|
||||||
|
|
||||||
# 0.0.11
|
# 0.0.11
|
||||||
- Fix redirects to /login for auth required pages
|
- Fix redirects to /login for auth required pages
|
||||||
- Add handling for 401/429 + No connection responses in API calls
|
- Add handling for 401/429 + No connection responses in API calls
|
||||||
@ -22,7 +28,7 @@
|
|||||||
|
|
||||||
# 0.0.8
|
# 0.0.8
|
||||||
- Added Admin/Site config page in frontend for admin users
|
- Added Admin/Site config page in frontend for admin users
|
||||||
- Added API POST/GET /config endpoint
|
- Added API POST/GET /config endpointnpm install react-select-timezone
|
||||||
|
|
||||||
# 0.0.7
|
# 0.0.7
|
||||||
- Switch redux -> Context
|
- Switch redux -> Context
|
||||||
|
@ -11,6 +11,10 @@ type Config struct {
|
|||||||
Setting map[string]string `json:"configs"`
|
Setting map[string]string `json:"configs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServerInfo struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
func getAllConfigs() (Config, error) {
|
func getAllConfigs() (Config, error) {
|
||||||
config := Config{}
|
config := Config{}
|
||||||
configs := make(map[string]string)
|
configs := make(map[string]string)
|
||||||
|
@ -4,63 +4,70 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MultiScrobblerInput struct {
|
||||||
|
Artists []string `json:"artists"`
|
||||||
|
Album string `json:"album"`
|
||||||
|
Track string `json:"track"`
|
||||||
|
PlayedAt time.Time `json:"playDate"`
|
||||||
|
Duration string `json:"duration"`
|
||||||
|
}
|
||||||
|
|
||||||
// ParseMultiScrobblerInput - Transform API data
|
// ParseMultiScrobblerInput - Transform API data
|
||||||
func ParseMultiScrobblerInput(userUUID string, data map[string]interface{}, ip net.IP, tx *sql.Tx) error {
|
func ParseMultiScrobblerInput(userUUID string, data map[string]interface{}, ip net.IP, tx *sql.Tx) error {
|
||||||
// Debugging
|
// Debugging
|
||||||
fmt.Printf("%+v", data)
|
fmt.Printf("%+v", data)
|
||||||
|
|
||||||
// if data["ItemType"] != "Audio" {
|
|
||||||
// return errors.New("Media type not audio")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Safety Checks
|
// // Safety Checks
|
||||||
// if data["Artist"] == nil {
|
// if data["artists"] == nil {
|
||||||
// return errors.New("Missing artist data")
|
// return errors.New("Missing artist data")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if data["Album"] == nil {
|
// if data["album"] == nil {
|
||||||
// return errors.New("Missing album data")
|
// return errors.New("Missing album data")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if data["Name"] == nil {
|
// if data["track"] == nil {
|
||||||
// return errors.New("Missing track data")
|
// return errors.New("Missing track data")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // Insert artist if not exist
|
// // Insert track artists
|
||||||
// artist, err := insertArtist(fmt.Sprintf("%s", data["Artist"]), fmt.Sprintf("%s", data["Provider_musicbrainzartist"]), tx)
|
// for _, artist := range data["artists"] {
|
||||||
// if err != nil {
|
// artist, err := insertArtist(artist.Name, "", artist.ID.String(), tx)
|
||||||
// log.Printf("%+v", err)
|
|
||||||
// return errors.New("Failed to map artist")
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// log.Printf("%+v", err)
|
||||||
|
// return errors.New("Failed to map artist: " + artist.Name)
|
||||||
|
// }
|
||||||
|
// artists = append(artists, artist.Uuid)
|
||||||
|
// }
|
||||||
// // Insert album if not exist
|
// // Insert album if not exist
|
||||||
// artists := []string{artist.Uuid}
|
// artists := []string{artist.Uuid}
|
||||||
// album, err := insertAlbum(fmt.Sprintf("%s", data["Album"]), fmt.Sprintf("%s", data["Provider_musicbrainzalbum"]), artists, tx)
|
// album, err := insertAlbum(fmt.Sprintf("%s", data["Album"]), fmt.Sprintf("%s", data["Provider_musicbrainzalbum"]), "", artists, tx)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Printf("%+v", err)
|
// log.Printf("%+v", err)
|
||||||
// return errors.New("Failed to map album")
|
// return errors.New("Failed to map album")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // Insert album if not exist
|
// // Insert track if not exist
|
||||||
// track, err := insertTrack(fmt.Sprintf("%s", data["Name"]), fmt.Sprintf("%s", data["Provider_musicbrainztrack"]), album.Uuid, artists, tx)
|
// length := timestampToSeconds(fmt.Sprintf("%s", data["RunTime"]))
|
||||||
|
// track, err := insertTrack(fmt.Sprintf("%s", data["Name"]), length, fmt.Sprintf("%s", data["Provider_musicbrainztrack"]), "", album.Uuid, artists, tx)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Printf("%+v", err)
|
// log.Printf("%+v", err)
|
||||||
// return errors.New("Failed to map track")
|
// return errors.New("Failed to map track")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // Insert album if not exist
|
// // Insert scrobble if not exist
|
||||||
// err = insertScrobble(userUUID, track.Uuid, "jellyfin", ip, tx)
|
// timestamp := time.Now()
|
||||||
|
// fmt.Println(timestamp)
|
||||||
|
// err = insertScrobble(userUUID, track.Uuid, "jellyfin", timestamp, ip, tx)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Printf("%+v", err)
|
// log.Printf("%+v", err)
|
||||||
// return errors.New("Failed to map track")
|
// return errors.New("Failed to map track")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// _ = album
|
|
||||||
// _ = artist
|
|
||||||
// _ = track
|
|
||||||
|
|
||||||
// Insert track if not exist
|
// Insert track if not exist
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,6 @@ func (user *User) updateSpotifyPlaydata() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
fmt.Printf("Updated spotify track: %+v", v.Track.Name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func HandleRequests(port string) {
|
|||||||
|
|
||||||
// JWT Auth - Own profile only (Uses uuid in JWT)
|
// JWT Auth - Own profile only (Uses uuid in JWT)
|
||||||
v1.HandleFunc("/user", limitMiddleware(jwtMiddleware(fetchUser), lightLimiter)).Methods("GET")
|
v1.HandleFunc("/user", limitMiddleware(jwtMiddleware(fetchUser), lightLimiter)).Methods("GET")
|
||||||
// v1.HandleFunc("/user", jwtMiddleware(fetchScrobbleResponse)).Methods("PATCH")
|
v1.HandleFunc("/user", limitMiddleware(jwtMiddleware(patchUser), lightLimiter)).Methods("PATCH")
|
||||||
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(getSpotifyClientID), lightLimiter)).Methods("GET")
|
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(getSpotifyClientID), lightLimiter)).Methods("GET")
|
||||||
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(deleteSpotifyLink), lightLimiter)).Methods("DELETE")
|
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(deleteSpotifyLink), lightLimiter)).Methods("DELETE")
|
||||||
v1.HandleFunc("/user/{uuid}/scrobbles", jwtMiddleware(fetchScrobbleResponse)).Methods("GET")
|
v1.HandleFunc("/user/{uuid}/scrobbles", jwtMiddleware(fetchScrobbleResponse)).Methods("GET")
|
||||||
@ -55,6 +55,7 @@ func HandleRequests(port string) {
|
|||||||
v1.HandleFunc("/login", limitMiddleware(handleLogin, standardLimiter)).Methods("POST")
|
v1.HandleFunc("/login", limitMiddleware(handleLogin, standardLimiter)).Methods("POST")
|
||||||
v1.HandleFunc("/sendreset", limitMiddleware(handleSendReset, heavyLimiter)).Methods("POST")
|
v1.HandleFunc("/sendreset", limitMiddleware(handleSendReset, heavyLimiter)).Methods("POST")
|
||||||
v1.HandleFunc("/resetpassword", limitMiddleware(handleResetPassword, heavyLimiter)).Methods("POST")
|
v1.HandleFunc("/resetpassword", limitMiddleware(handleResetPassword, heavyLimiter)).Methods("POST")
|
||||||
|
v1.HandleFunc("/serverinfo", fetchServerInfo).Methods("GET")
|
||||||
|
|
||||||
// Redirect from Spotify Oauth
|
// Redirect from Spotify Oauth
|
||||||
v1.HandleFunc("/link/spotify", limitMiddleware(postSpotifyReponse, lightLimiter))
|
v1.HandleFunc("/link/spotify", limitMiddleware(postSpotifyReponse, lightLimiter))
|
||||||
@ -67,11 +68,12 @@ func HandleRequests(port string) {
|
|||||||
r.PathPrefix("/").Handler(spa)
|
r.PathPrefix("/").Handler(spa)
|
||||||
|
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
// Grrrr CORS. To clean up at a later date
|
|
||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
AllowCredentials: true,
|
AllowCredentials: true,
|
||||||
|
AllowedMethods: []string{"GET", "POST", "PATCH", "DELETE"},
|
||||||
AllowedHeaders: []string{"*"},
|
AllowedHeaders: []string{"*"},
|
||||||
})
|
})
|
||||||
|
|
||||||
handler := c.Handler(r)
|
handler := c.Handler(r)
|
||||||
|
|
||||||
// Serve it up!
|
// Serve it up!
|
||||||
@ -219,6 +221,7 @@ func handleResetPassword(w http.ResponseWriter, r *http.Request) {
|
|||||||
// serveEndpoint - API stuffs
|
// serveEndpoint - API stuffs
|
||||||
func handleIngress(w http.ResponseWriter, r *http.Request, userUuid string) {
|
func handleIngress(w http.ResponseWriter, r *http.Request, userUuid string) {
|
||||||
bodyJson, err := decodeJson(r.Body)
|
bodyJson, err := decodeJson(r.Body)
|
||||||
|
fmt.Println(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwInvalidJson(w)
|
throwInvalidJson(w)
|
||||||
return
|
return
|
||||||
@ -291,6 +294,29 @@ func fetchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser s
|
|||||||
w.Write(json)
|
w.Write(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// patchUser - Update specific values
|
||||||
|
func patchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
||||||
|
userFull, err := getUser(jwtUser)
|
||||||
|
if err != nil {
|
||||||
|
throwOkError(w, "Failed to fetch user information")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyJson, _ := decodeJson(r.Body)
|
||||||
|
|
||||||
|
ip := getUserIp(r)
|
||||||
|
for k, v := range bodyJson {
|
||||||
|
val := fmt.Sprintf("%s", v)
|
||||||
|
if k == "timezone" {
|
||||||
|
if isValidTimezone(val) {
|
||||||
|
userFull.updateUser("timezone", val, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throwOkMessage(w, "User updated successfully")
|
||||||
|
}
|
||||||
|
|
||||||
// fetchScrobbles - Return an array of scrobbles
|
// fetchScrobbles - Return an array of scrobbles
|
||||||
func fetchScrobbleResponse(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
func fetchScrobbleResponse(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
||||||
resp, err := fetchScrobblesForUser(reqUser, 100, 1)
|
resp, err := fetchScrobblesForUser(reqUser, 100, 1)
|
||||||
@ -408,3 +434,13 @@ func deleteSpotifyLink(w http.ResponseWriter, r *http.Request, u string, v strin
|
|||||||
|
|
||||||
throwOkMessage(w, "Spotify account successfully unlinked")
|
throwOkMessage(w, "Spotify account successfully unlinked")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
info := ServerInfo{
|
||||||
|
Version: "0.0.11",
|
||||||
|
}
|
||||||
|
|
||||||
|
js, _ := json.Marshal(&info)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(js)
|
||||||
|
}
|
||||||
|
@ -20,14 +20,21 @@ var lightLimiter = NewIPRateLimiter(10, 10)
|
|||||||
// tokenMiddleware - Validates token to a user
|
// tokenMiddleware - Validates token to a user
|
||||||
func tokenMiddleware(next func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
func tokenMiddleware(next func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
fullToken := r.Header.Get("Authorization")
|
key := ""
|
||||||
authToken := strings.Replace(fullToken, "Bearer ", "", 1)
|
urlParams := r.URL.Query()
|
||||||
if authToken == "" {
|
if val, ok := urlParams["key"]; ok {
|
||||||
|
key = val[0]
|
||||||
|
} else {
|
||||||
|
throwUnauthorized(w, "No key parameter provided")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == "" {
|
||||||
throwUnauthorized(w, "A token is required")
|
throwUnauthorized(w, "A token is required")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userUuid, err := getUserUuidForToken(authToken)
|
userUuid, err := getUserUuidForToken(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwUnauthorized(w, err.Error())
|
throwUnauthorized(w, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -156,14 +156,14 @@ func insertUser(username string, email string, password []byte, ip net.IP) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUser(uuid string, field string, value string, ip net.IP) error {
|
func (user *User) updateUser(field string, value string, ip net.IP) error {
|
||||||
_, err := db.Exec("UPDATE users SET `"+field+"` = ?, modified_at = NOW(), modified_ip = ? WHERE uuid = ?", value, uuid, ip)
|
_, err := db.Exec("UPDATE users SET `"+field+"` = ?, modified_at = NOW(), modified_ip = ? WHERE uuid = UUID_TO_BIN(?, true)", value, ip, user.UUID)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUserDirect(uuid string, field string, value string) error {
|
func (user *User) updateUserDirect(field string, value string) error {
|
||||||
_, err := db.Exec("UPDATE users SET `"+field+"` = ? WHERE uuid = ?", value, uuid)
|
_, err := db.Exec("UPDATE users SET `"+field+"` = ? WHERE uuid = UUID_TO_BIN(?, true)", value, user.UUID)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
||||||
@ -79,6 +80,10 @@ func getUserIp(r *http.Request) net.IP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if host == "" {
|
||||||
|
host = "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
ip = net.ParseIP(host)
|
ip = net.ParseIP(host)
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
@ -144,3 +149,8 @@ func filterSlice(s []string) []string {
|
|||||||
fmt.Printf("RESTULS: %+v", result)
|
fmt.Printf("RESTULS: %+v", result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValidTimezone(tz string) bool {
|
||||||
|
_, err := time.LoadLocation(tz)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `users` (
|
CREATE TABLE IF NOT EXISTS `users` (
|
||||||
`uuid` BINARY(16) PRIMARY KEY,
|
`uuid` BINARY(16) PRIMARY KEY,
|
||||||
`created_at` DATETIME NOT NULL,
|
`created_at` DATETIME NOT NULL DEFAULT NOW(),
|
||||||
`created_ip` VARBINARY(16) NULL DEFAULT NULL,
|
`created_ip` VARBINARY(16) NULL DEFAULT NULL,
|
||||||
`modified_at` DATETIME NOT NULL,
|
`modified_at` DATETIME NOT NULL DEFAULT NOW(),
|
||||||
`modified_ip` VARBINARY(16) NULL DEFAULT NULL,
|
`modified_ip` VARBINARY(16) NULL DEFAULT NULL,
|
||||||
`username` VARCHAR(64) NOT NULL,
|
`username` VARCHAR(64) NOT NULL,
|
||||||
`password` VARCHAR(60) NOT NULL,
|
`password` VARCHAR(60) NOT NULL,
|
||||||
|
345
web/package-lock.json
generated
345
web/package-lock.json
generated
@ -22,10 +22,10 @@
|
|||||||
"react-bootstrap": "^1.5.2",
|
"react-bootstrap": "^1.5.2",
|
||||||
"react-cookie": "^4.0.3",
|
"react-cookie": "^4.0.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-redux": "^7.2.3",
|
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-spinners": "^0.10.6",
|
"react-spinners": "^0.10.6",
|
||||||
|
"react-timezone-select": "^0.10.7",
|
||||||
"react-toastify": "^7.0.3",
|
"react-toastify": "^7.0.3",
|
||||||
"reactstrap": "^8.9.0"
|
"reactstrap": "^8.9.0"
|
||||||
},
|
},
|
||||||
@ -1518,6 +1518,66 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
||||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@emotion/react": {
|
||||||
|
"version": "11.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.1.5.tgz",
|
||||||
|
"integrity": "sha512-xfnZ9NJEv9SU9K2sxXM06lzjK245xSeHRpUh67eARBm3PBHjjKIZlfWZ7UQvD0Obvw6ZKjlC79uHrlzFYpOB/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.7.2",
|
||||||
|
"@emotion/cache": "^11.1.3",
|
||||||
|
"@emotion/serialize": "^1.0.0",
|
||||||
|
"@emotion/sheet": "^1.0.1",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"hoist-non-react-statics": "^3.3.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0",
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@babel/core": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/react/node_modules/@emotion/cache": {
|
||||||
|
"version": "11.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
|
||||||
|
"integrity": "sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/sheet": "^1.0.0",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"stylis": "^4.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/react/node_modules/@emotion/serialize": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-TXlKs5sgUKhFlszp/rg4lIAZd7UUSmJpwaf9/lAEFcUh2vPi32i7x4wk7O8TN8L8v2Ol8k0CxnhRBY0zQalTxA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/hash": "^0.8.0",
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/unitless": "^0.7.5",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/react/node_modules/@emotion/sheet": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g=="
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/react/node_modules/@emotion/utils": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
|
||||||
|
},
|
||||||
"node_modules/@emotion/serialize": {
|
"node_modules/@emotion/serialize": {
|
||||||
"version": "0.11.16",
|
"version": "0.11.16",
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz",
|
||||||
@ -3390,17 +3450,6 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-redux": {
|
|
||||||
"version": "7.1.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
|
|
||||||
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/hoist-non-react-statics": "^3.3.0",
|
|
||||||
"@types/react": "*",
|
|
||||||
"hoist-non-react-statics": "^3.3.0",
|
|
||||||
"redux": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/react-transition-group": {
|
"node_modules/@types/react-transition-group": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||||
@ -13463,6 +13512,11 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/memoize-one": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
|
||||||
|
},
|
||||||
"node_modules/memory-fs": {
|
"node_modules/memory-fs": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||||
@ -16713,6 +16767,17 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-input-autosize": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.5.8"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.3.0 || ^17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
@ -16759,36 +16824,6 @@
|
|||||||
"react": "0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
"react": "0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-redux": {
|
|
||||||
"version": "7.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.3.tgz",
|
|
||||||
"integrity": "sha512-ZhAmQ1lrK+Pyi0ZXNMUZuYxYAZd59wFuVDGUt536kSGdD0ya9Q7BfsE95E3TsFLE3kOSFp5m6G5qbatE+Ic1+w==",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": "^7.12.1",
|
|
||||||
"@types/react-redux": "^7.1.16",
|
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
|
||||||
"loose-envify": "^1.4.0",
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"react-is": "^16.13.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.8.3 || ^17",
|
|
||||||
"redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"react-dom": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-native": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-redux/node_modules/react-is": {
|
|
||||||
"version": "16.13.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
|
||||||
},
|
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
||||||
@ -16973,6 +17008,46 @@
|
|||||||
"semver": "bin/semver"
|
"semver": "bin/semver"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-select": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-select/-/react-select-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-SBPD1a3TJqE9zoI/jfOLCAoLr/neluaeokjOixr3zZ1vHezkom8K0A9J4QG9IWDqIDE9K/Mv+0y1GjidC2PDtQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.0",
|
||||||
|
"@emotion/cache": "^11.0.0",
|
||||||
|
"@emotion/react": "^11.1.1",
|
||||||
|
"memoize-one": "^5.0.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-input-autosize": "^3.0.0",
|
||||||
|
"react-transition-group": "^4.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-select/node_modules/@emotion/cache": {
|
||||||
|
"version": "11.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
|
||||||
|
"integrity": "sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/sheet": "^1.0.0",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"stylis": "^4.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-select/node_modules/@emotion/sheet": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g=="
|
||||||
|
},
|
||||||
|
"node_modules/react-select/node_modules/@emotion/utils": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
|
||||||
|
},
|
||||||
"node_modules/react-spinners": {
|
"node_modules/react-spinners": {
|
||||||
"version": "0.10.6",
|
"version": "0.10.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.10.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.10.6.tgz",
|
||||||
@ -16985,6 +17060,20 @@
|
|||||||
"react-dom": "^16.0.0 || ^17.0.0"
|
"react-dom": "^16.0.0 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-timezone-select": {
|
||||||
|
"version": "0.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-timezone-select/-/react-timezone-select-0.10.7.tgz",
|
||||||
|
"integrity": "sha512-JPnrYcXf3NqqNl4HYDsDaS6OiUEPW6i7xeGE1xOA7SPuh7oR5vzKj0g0kbg5IH8LkiWTZNWk5NbBSJkRHp/dlA==",
|
||||||
|
"dependencies": {
|
||||||
|
"react-select": "^4.0.2",
|
||||||
|
"spacetime": "^6.12.3",
|
||||||
|
"spacetime-informal": "^0.5.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^17.0.1",
|
||||||
|
"react-dom": "^17.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-toastify": {
|
"node_modules/react-toastify": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.3.tgz",
|
||||||
@ -18851,6 +18940,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
|
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/spacetime": {
|
||||||
|
"version": "6.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spacetime/-/spacetime-6.14.0.tgz",
|
||||||
|
"integrity": "sha512-pz/nMIRGNSJeFfDFvhPjMHXhFU1NcrYnpydMuSS2Zsk0NEoHJc2rRKXugkmlqUv/l/fPxWVJVnj8isVS0//vbQ=="
|
||||||
|
},
|
||||||
|
"node_modules/spacetime-informal": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spacetime-informal/-/spacetime-informal-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-cdSsniJJfJJTBdeVvXtooxyXzrRfoBVjAl3usQl9DgGExB3XN3deA3MwjInnD/26C/lANf3dU54bT2YweAGrOw=="
|
||||||
|
},
|
||||||
"node_modules/spdx-correct": {
|
"node_modules/spdx-correct": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
||||||
@ -19408,6 +19507,11 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stylis": {
|
||||||
|
"version": "4.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.9.tgz",
|
||||||
|
"integrity": "sha512-ci7pEFNVW3YJiWEzqPOMsAjY6kgraZ3ZgBfQ5HYbNtLJEsQ0G46ejWZpfSSCp/FaSiCSGGhzL9O2lN+2cB6ong=="
|
||||||
|
},
|
||||||
"node_modules/supports-color": {
|
"node_modules/supports-color": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
@ -23661,6 +23765,56 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
||||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
||||||
},
|
},
|
||||||
|
"@emotion/react": {
|
||||||
|
"version": "11.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.1.5.tgz",
|
||||||
|
"integrity": "sha512-xfnZ9NJEv9SU9K2sxXM06lzjK245xSeHRpUh67eARBm3PBHjjKIZlfWZ7UQvD0Obvw6ZKjlC79uHrlzFYpOB/Q==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.7.2",
|
||||||
|
"@emotion/cache": "^11.1.3",
|
||||||
|
"@emotion/serialize": "^1.0.0",
|
||||||
|
"@emotion/sheet": "^1.0.1",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"hoist-non-react-statics": "^3.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/cache": {
|
||||||
|
"version": "11.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
|
||||||
|
"integrity": "sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==",
|
||||||
|
"requires": {
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/sheet": "^1.0.0",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"stylis": "^4.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@emotion/serialize": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-TXlKs5sgUKhFlszp/rg4lIAZd7UUSmJpwaf9/lAEFcUh2vPi32i7x4wk7O8TN8L8v2Ol8k0CxnhRBY0zQalTxA==",
|
||||||
|
"requires": {
|
||||||
|
"@emotion/hash": "^0.8.0",
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/unitless": "^0.7.5",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@emotion/sheet": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g=="
|
||||||
|
},
|
||||||
|
"@emotion/utils": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@emotion/serialize": {
|
"@emotion/serialize": {
|
||||||
"version": "0.11.16",
|
"version": "0.11.16",
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz",
|
||||||
@ -25055,17 +25209,6 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-redux": {
|
|
||||||
"version": "7.1.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
|
|
||||||
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
|
|
||||||
"requires": {
|
|
||||||
"@types/hoist-non-react-statics": "^3.3.0",
|
|
||||||
"@types/react": "*",
|
|
||||||
"hoist-non-react-statics": "^3.3.0",
|
|
||||||
"redux": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/react-transition-group": {
|
"@types/react-transition-group": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||||
@ -32905,6 +33048,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||||
},
|
},
|
||||||
|
"memoize-one": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
|
||||||
|
},
|
||||||
"memory-fs": {
|
"memory-fs": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||||
@ -35510,6 +35658,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||||
},
|
},
|
||||||
|
"react-input-autosize": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==",
|
||||||
|
"requires": {
|
||||||
|
"prop-types": "^15.5.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
@ -35549,26 +35705,6 @@
|
|||||||
"warning": "^4.0.2"
|
"warning": "^4.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-redux": {
|
|
||||||
"version": "7.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.3.tgz",
|
|
||||||
"integrity": "sha512-ZhAmQ1lrK+Pyi0ZXNMUZuYxYAZd59wFuVDGUt536kSGdD0ya9Q7BfsE95E3TsFLE3kOSFp5m6G5qbatE+Ic1+w==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.12.1",
|
|
||||||
"@types/react-redux": "^7.1.16",
|
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
|
||||||
"loose-envify": "^1.4.0",
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"react-is": "^16.13.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"react-is": {
|
|
||||||
"version": "16.13.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-refresh": {
|
"react-refresh": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
||||||
@ -35723,6 +35859,44 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-select": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-select/-/react-select-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-SBPD1a3TJqE9zoI/jfOLCAoLr/neluaeokjOixr3zZ1vHezkom8K0A9J4QG9IWDqIDE9K/Mv+0y1GjidC2PDtQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.12.0",
|
||||||
|
"@emotion/cache": "^11.0.0",
|
||||||
|
"@emotion/react": "^11.1.1",
|
||||||
|
"memoize-one": "^5.0.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-input-autosize": "^3.0.0",
|
||||||
|
"react-transition-group": "^4.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/cache": {
|
||||||
|
"version": "11.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
|
||||||
|
"integrity": "sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==",
|
||||||
|
"requires": {
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/sheet": "^1.0.0",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"stylis": "^4.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@emotion/sheet": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g=="
|
||||||
|
},
|
||||||
|
"@emotion/utils": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-spinners": {
|
"react-spinners": {
|
||||||
"version": "0.10.6",
|
"version": "0.10.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.10.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.10.6.tgz",
|
||||||
@ -35731,6 +35905,16 @@
|
|||||||
"@emotion/core": "^10.0.35"
|
"@emotion/core": "^10.0.35"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-timezone-select": {
|
||||||
|
"version": "0.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-timezone-select/-/react-timezone-select-0.10.7.tgz",
|
||||||
|
"integrity": "sha512-JPnrYcXf3NqqNl4HYDsDaS6OiUEPW6i7xeGE1xOA7SPuh7oR5vzKj0g0kbg5IH8LkiWTZNWk5NbBSJkRHp/dlA==",
|
||||||
|
"requires": {
|
||||||
|
"react-select": "^4.0.2",
|
||||||
|
"spacetime": "^6.12.3",
|
||||||
|
"spacetime-informal": "^0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-toastify": {
|
"react-toastify": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.3.tgz",
|
||||||
@ -37221,6 +37405,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
|
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
|
||||||
},
|
},
|
||||||
|
"spacetime": {
|
||||||
|
"version": "6.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spacetime/-/spacetime-6.14.0.tgz",
|
||||||
|
"integrity": "sha512-pz/nMIRGNSJeFfDFvhPjMHXhFU1NcrYnpydMuSS2Zsk0NEoHJc2rRKXugkmlqUv/l/fPxWVJVnj8isVS0//vbQ=="
|
||||||
|
},
|
||||||
|
"spacetime-informal": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spacetime-informal/-/spacetime-informal-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-cdSsniJJfJJTBdeVvXtooxyXzrRfoBVjAl3usQl9DgGExB3XN3deA3MwjInnD/26C/lANf3dU54bT2YweAGrOw=="
|
||||||
|
},
|
||||||
"spdx-correct": {
|
"spdx-correct": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
||||||
@ -37668,6 +37862,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"stylis": {
|
||||||
|
"version": "4.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.9.tgz",
|
||||||
|
"integrity": "sha512-ci7pEFNVW3YJiWEzqPOMsAjY6kgraZ3ZgBfQ5HYbNtLJEsQ0G46ejWZpfSSCp/FaSiCSGGhzL9O2lN+2cB6ong=="
|
||||||
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"react-bootstrap": "^1.5.2",
|
"react-bootstrap": "^1.5.2",
|
||||||
"react-cookie": "^4.0.3",
|
"react-cookie": "^4.0.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-redux": "^7.2.3",
|
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-spinners": "^0.10.6",
|
"react-spinners": "^0.10.6",
|
||||||
|
"react-timezone-select": "^0.10.7",
|
||||||
"react-toastify": "^7.0.3",
|
"react-toastify": "^7.0.3",
|
||||||
"reactstrap": "^8.9.0"
|
"reactstrap": "^8.9.0"
|
||||||
},
|
},
|
||||||
|
@ -3,18 +3,24 @@ import jwt from 'jwt-decode'
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
function getHeaders() {
|
function getHeaders() {
|
||||||
// Todo: move this to use Context values instead.
|
// TODO: move this to use Context values instead.
|
||||||
const user = JSON.parse(localStorage.getItem('user'));
|
const user = JSON.parse(localStorage.getItem('user'));
|
||||||
|
|
||||||
if (user && user.jwt) {
|
if (user && user.jwt) {
|
||||||
return { Authorization: 'Bearer ' + user.jwt, changeOrigin: true };
|
var unixtime = Math.round((new Date()).getTime() / 1000);
|
||||||
|
if (user.exp < unixtime) {
|
||||||
|
// TODO: Handle expiry nicer
|
||||||
|
toast.warning("Session expired. Please log in again")
|
||||||
|
}
|
||||||
|
|
||||||
|
return { Authorization: 'Bearer ' + user.jwt };
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserUuid() {
|
function getUserUuid() {
|
||||||
// Todo: move this to use Context values instead.
|
// TODO: move this to use Context values instead.
|
||||||
const user = JSON.parse(localStorage.getItem('user'));
|
const user = JSON.parse(localStorage.getItem('user'));
|
||||||
|
|
||||||
if (user && user.uuid) {
|
if (user && user.uuid) {
|
||||||
@ -179,6 +185,15 @@ export const getUser = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const patchUser = (values) => {
|
||||||
|
return axios.patch(process.env.REACT_APP_API_URL + "user", values, { headers: getHeaders() })
|
||||||
|
.then((data) => {
|
||||||
|
return data.data;
|
||||||
|
}).catch((error) => {
|
||||||
|
return handleErrorResp(error)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const validateResetPassword = (tokenStr) => {
|
export const validateResetPassword = (tokenStr) => {
|
||||||
return axios.get(process.env.REACT_APP_API_URL + "user/", { headers: getHeaders() })
|
return axios.get(process.env.REACT_APP_API_URL + "user/", { headers: getHeaders() })
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
@ -2,3 +2,8 @@
|
|||||||
padding: 20px 5px 5px 5px;
|
padding: 20px 5px 5px 5px;
|
||||||
font-size: 16pt;
|
font-size: 16pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.userDropdown {
|
||||||
|
color: #282C34;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
@ -4,9 +4,11 @@ import './User.css';
|
|||||||
import { useHistory } from "react-router";
|
import { useHistory } from "react-router";
|
||||||
import AuthContext from '../Contexts/AuthContext';
|
import AuthContext from '../Contexts/AuthContext';
|
||||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||||
import { getUser } from '../Api/index'
|
import { getUser, patchUser } from '../Api/index'
|
||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
|
|
||||||
import { spotifyConnectionRequest, spotifyDisonnectionRequest } from '../Api/index'
|
import { spotifyConnectionRequest, spotifyDisonnectionRequest } from '../Api/index'
|
||||||
|
import TimezoneSelect from 'react-timezone-select'
|
||||||
|
|
||||||
const User = () => {
|
const User = () => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@ -14,6 +16,11 @@ const User = () => {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [userdata, setUserdata] = useState({});
|
const [userdata, setUserdata] = useState({});
|
||||||
|
|
||||||
|
const updateTimezone = (vals) => {
|
||||||
|
console.log(vals)
|
||||||
|
setUserdata({...userdata, timezone: vals});
|
||||||
|
patchUser({timezone: vals.value})
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
@ -45,6 +52,12 @@ const User = () => {
|
|||||||
Welcome {userdata.username}
|
Welcome {userdata.username}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="userBody">
|
<p className="userBody">
|
||||||
|
Timezone<br/>
|
||||||
|
<TimezoneSelect
|
||||||
|
className="userDropdown"
|
||||||
|
value={userdata.timezone}
|
||||||
|
onChange={updateTimezone}
|
||||||
|
/><br/>
|
||||||
Created At: {userdata.created_at}<br/>
|
Created At: {userdata.created_at}<br/>
|
||||||
Email: {userdata.email}<br/>
|
Email: {userdata.email}<br/>
|
||||||
Verified: {userdata.verified ? '✓' : '✖'}<br/>
|
Verified: {userdata.verified ? '✓' : '✖'}<br/>
|
||||||
|
Loading…
Reference in New Issue
Block a user