diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 9ed398f7..db2e91ab 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -181,6 +181,7 @@ type User struct { Id string `datastore:"id" json:"id"` Orgs []string `datastore:"orgs" json:"orgs"` CreationTime int64 `datastore:"creation_time" json:"creation_time"` + ActiveOrg Org `json:"active_org" datastore:"active_org"` Active bool `datastore:"active" json:"active"` } @@ -1013,13 +1014,13 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) { user, err := handleApiAuthentication(resp, request) if err != nil { resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "Can't register without being admin"}`)) + resp.Write([]byte(`{"success": false, "reason": "Can't handle set env auth"}`)) return } if user.Role != "admin" { resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "Can't register without being admin"}`)) + resp.Write([]byte(`{"success": false, "reason": "Can't set environment without being admin"}`)) return } @@ -1097,7 +1098,7 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) { resp.Write([]byte(`{"success": true}`)) } -func createNewUser(username, password, role, apikey string) error { +func createNewUser(username, password, role, apikey string, org Org) error { // Returns false if there is an issue // Use this for register err := checkPasswordStrength(password) @@ -1137,7 +1138,7 @@ func createNewUser(username, password, role, apikey string) error { newUser.Verified = false newUser.CreationTime = time.Now().Unix() newUser.Active = true - newUser.Orgs = []string{"default"} + newUser.Orgs = []string{org.Id} // FIXME - Remove this later if role == "admin" { @@ -1148,6 +1149,8 @@ func createNewUser(username, password, role, apikey string) error { newUser.Roles = []string{"user"} } + newUser.ActiveOrg = org + if len(apikey) > 0 { newUser.ApiKey = apikey } @@ -1182,25 +1185,25 @@ func createNewUser(username, password, role, apikey string) error { log.Printf("Error adding User %s: %s", username, err) return err } - url := fmt.Sprintf("https://shuffler.io/register/%s", verifyToken.String()) - const verifyMessage = ` -Registration URL :) - -%s - ` - addr := newUser.Username - - msg := &mail.Message{ - Sender: "Shuffle ", - To: []string{addr}, - Subject: "Verify your username - Shuffle", - Body: fmt.Sprintf(verifyMessage, url), - } - - log.Println(msg.Body) - if err := mail.Send(ctx, msg); err != nil { - log.Printf("Couldn't send email: %v", err) - } + // url := fmt.Sprintf("https://shuffler.io/register/%s", verifyToken.String()) + // const verifyMessage = ` + //Registration URL :) + // + //%s + // ` + // addr := newUser.Username + // + // msg := &mail.Message{ + // Sender: "Shuffle ", + // To: []string{addr}, + // Subject: "Verify your username - Shuffle", + // Body: fmt.Sprintf(verifyMessage, url), + // } + // + // log.Println(msg.Body) + // if err := mail.Send(ctx, msg); err != nil { + // log.Printf("Couldn't send email: %v", err) + // } err = increaseStatisticsField(ctx, "successful_register", username, 1) if err != nil { @@ -1249,7 +1252,8 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) { if count == 0 { role = "admin" } - err = createNewUser(data.Username, data.Password, role, "") + + err = createNewUser(data.Username, data.Password, role, "", user.ActiveOrg) if err != nil { log.Printf("Failed registering user: %s", err) resp.WriteHeader(401) @@ -1623,6 +1627,10 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { // This is a long check to see if an inactive admin can access the site parsedAdmin := "false" + if userInfo.Role == "admin" { + parsedAdmin = "true" + } + if !userInfo.Active { if userInfo.Role == "admin" { parsedAdmin = "true" @@ -1692,14 +1700,55 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { Expires: expiration, }) - // Migrate this to real Org - // Need to create org endpoints (create, delete etc) - currentOrg := `{ - "name": "Shuffle", - "id": "123", - "role": "admin", - "cloud_sync": false - }` + // Updating user info if there's something wrong + if (len(userInfo.ActiveOrg.Name) == 0 || len(userInfo.ActiveOrg.Id) == 0) && len(userInfo.Orgs) > 0 { + _, err := getOrg(ctx, userInfo.Orgs[0]) + if err != nil { + var orgs []Org + q := datastore.NewQuery("Organizations") + _, err = dbclient.GetAll(ctx, q, &orgs) + if err == nil { + newStringOrgs := []string{} + newOrgs := []Org{} + for _, org := range orgs { + if strings.ToLower(org.Name) == strings.ToLower(userInfo.Orgs[0]) { + newOrgs = append(newOrgs, org) + newStringOrgs = append(newStringOrgs, org.Id) + } + } + + if len(newOrgs) > 0 { + userInfo.ActiveOrg = newOrgs[0] + userInfo.Orgs = newStringOrgs + + err = setUser(ctx, &userInfo) + if err != nil { + log.Printf("Error patching User for activeOrg: %s", err) + } else { + log.Printf("Updated the users' org") + } + } + } else { + log.Printf("Failed getting orgs for user. Major issue.: %s", err) + } + + } else { + // 1. Check if the org exists by ID + // 2. if it does, overwrite user + userInfo.ActiveOrg = Org{ + Id: userInfo.Orgs[0], + } + err = setUser(ctx, &userInfo) + if err != nil { + log.Printf("Error patching User for activeOrg: %s", err) + } + } + } + + currentOrg, err := json.Marshal(userInfo.ActiveOrg) + if err != nil { + currentOrg = []byte("{}") + } returnData := fmt.Sprintf(` { @@ -2175,6 +2224,61 @@ func handleGetEnvironments(resp http.ResponseWriter, request *http.Request) { resp.Write(newjson) } +func handleGetOrgs(resp http.ResponseWriter, request *http.Request) { + cors := handleCors(resp, request) + if cors { + return + } + + user, err := handleApiAuthentication(resp, request) + if err != nil { + log.Printf("Api authentication failed in set new workflowhandler: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + + if user.Role != "admin" { + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Not admin"}`)) + return + } + + ctx := context.Background() + var orgs []Org + q := datastore.NewQuery("Organizations") + _, err = dbclient.GetAll(ctx, q, &orgs) + if err != nil { + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Can't get users"}`)) + return + } + + //newUsers := []User{} + //for _, item := range users { + // if len(item.Username) == 0 { + // continue + // } + + // item.Password = "" + // item.Session = "" + // item.VerificationToken = "" + + // newUsers = append(newUsers, item) + //} + + newjson, err := json.Marshal(orgs) + if err != nil { + log.Printf("Failed unmarshal: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed unpacking"}`))) + return + } + + resp.WriteHeader(200) + resp.Write(newjson) +} + func handleGetUsers(resp http.ResponseWriter, request *http.Request) { cors := handleCors(resp, request) if cors { @@ -2392,6 +2496,28 @@ func getSession(ctx context.Context, thissession string) (*session, error) { return curUser, nil } +// ListBooks returns a list of books, ordered by title. +func getOrg(ctx context.Context, id string) (*Org, error) { + key := datastore.NameKey("Organizations", id, nil) + curOrg := &Org{} + if err := dbclient.Get(ctx, key, curOrg); err != nil { + return &Org{}, err + } + + return curOrg, nil +} + +func setOrg(ctx context.Context, data Org, id string) error { + // clear session_token and API_token for user + k := datastore.NameKey("Organizations", id, nil) + if _, err := dbclient.Put(ctx, k, &data); err != nil { + log.Println(err) + return err + } + + return nil +} + // ListBooks returns a list of books, ordered by title. func getUser(ctx context.Context, id string) (*User, error) { key := datastore.NameKey("Users", id, nil) @@ -4791,8 +4917,8 @@ func setTriggerAuth(ctx context.Context, trigger TriggerAuth) error { func getOutlookClient(ctx context.Context, code string, accessToken OauthToken, redirectUri string) (*http.Client, *oauth2.Token, error) { conf := &oauth2.Config{ - ClientID: "70e37005-c954-4290-b573-d4b94e484336", - ClientSecret: ".eNw/A[kQFB5zL.agvRputdEJENeJ392", + ClientID: "", + ClientSecret: "", Scopes: []string{ "Mail.Read", "User.Read", @@ -6243,6 +6369,91 @@ func runInit(ctx context.Context) { } */ + setUsers := false + orgQuery := datastore.NewQuery("Organizations") + var activeOrgs []Org + _, err = dbclient.GetAll(ctx, orgQuery, &activeOrgs) + if err != nil { + log.Printf("Error getting organizations!") + } else { + // Add all users to it + if len(activeOrgs) == 1 { + setUsers = true + } + + log.Printf("Organizations exist!") + if len(activeOrgs) == 0 { + log.Printf(`No orgs. Setting org "default"`) + orgSetupName := "default" + orgId := uuid.NewV4().String() + newOrg := Org{ + Name: orgSetupName, + Id: orgId, + Org: orgSetupName, + Users: []User{}, + Roles: []string{"admin", "user"}, + CloudSync: false, + } + + err = setOrg(ctx, newOrg, orgId) + if err != nil { + log.Printf("Failed setting organization: %s", err) + } else { + log.Printf("Successfully created the default org!") + setUsers = true + } + } else { + log.Printf("There are %d org(s).", len(activeOrgs)) + } + } + + // Adding the users to the base organization since only one exists (default) + if setUsers && len(activeOrgs) > 0 { + activeOrg := activeOrgs[0] + + q := datastore.NewQuery("Users") + var users []User + _, err = dbclient.GetAll(ctx, q, &users) + if err == nil { + setOrgBool := false + for _, user := range users { + newUser := User{ + Username: user.Username, + Id: user.Id, + ActiveOrg: Org{ + Id: activeOrg.Id, + }, + Orgs: []string{activeOrg.Id}, + Role: user.Role, + } + + found := false + for _, orgUser := range activeOrg.Users { + if user.Id == orgUser.Id { + found = true + } + } + + if !found && len(user.Username) > 0 { + log.Printf("Adding user %s to org %s", user.Username, activeOrg.Name) + activeOrg.Users = append(activeOrg.Users, newUser) + setOrgBool = true + } + } + + if setOrgBool { + err = setOrg(ctx, activeOrg, activeOrg.Id) + if err != nil { + log.Printf("Failed setting org %s: %s!", activeOrg.Name, err) + } else { + log.Printf("UPDATED org %s!", activeOrg.Name) + } + } + } + + log.Printf("Should add %d users to organization default", len(users)) + } + // Fix active users etc q := datastore.NewQuery("Users").Filter("active =", true) var activeusers []User @@ -6253,6 +6464,7 @@ func runInit(ctx context.Context) { q := datastore.NewQuery("Users") var users []User _, err := dbclient.GetAll(ctx, q, &users) + if len(activeusers) == 0 && len(users) > 0 { log.Printf("No active users found - setting ALL to active") if err == nil { @@ -6268,7 +6480,12 @@ func runInit(ctx context.Context) { } if len(user.Orgs) == 0 { - user.Orgs = []string{"default"} + defaultName := "default" + user.Orgs = []string{defaultName} + user.ActiveOrg = Org{ + Name: defaultName, + Role: "user", + } } err = setUser(ctx, &user) @@ -6291,7 +6508,11 @@ func runInit(ctx context.Context) { log.Printf("SHUFFLE_DEFAULT_USERNAME and SHUFFLE_DEFAULT_PASSWORD not defined as environments. Running without default user.") } else { apikey := os.Getenv("SHUFFLE_DEFAULT_APIKEY") - err = createNewUser(username, password, "admin", apikey) + + tmpOrg := Org{ + Name: "default", + } + err = createNewUser(username, password, "admin", apikey, tmpOrg) if err != nil { log.Printf("Failed to create default user %s: %s", username, err) } else { @@ -6504,6 +6725,31 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) { log.Printf("Apidata: %s", tmpData.Apikey) // FIXME: https://docs.google.com/drawings/d/1JJebpPeEVEbmH_qsAC6zf9Noygp7PytvesrkhE19QrY/edit + client := &http.Client{} + syncPath := "http://192.168.3.6:5002/api/v1/cloud/sync" + req, err := http.NewRequest( + "POST", + syncPath, + nil, + ) + + newresp, err := client.Do(req) + if err != nil { + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed cloud sync: %s"`, err))) + //setBadMemcache(ctx, docPath) + return + } + + respBody, err := ioutil.ReadAll(newresp.Body) + if err != nil { + resp.WriteHeader(500) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Can't parse sync data"`))) + return + } + + log.Printf("Respbody: %s", string(respBody)) + resp.WriteHeader(200) resp.Write([]byte(fmt.Sprintf(`{"success": true}`))) } @@ -6625,8 +6871,9 @@ func init() { r.HandleFunc("/api/v1/validate_openapi", validateSwagger).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/get_openapi/{key}", getOpenapi).Methods("GET", "OPTIONS") + // NEW for 0.8.0 r.HandleFunc("/api/v1/cloud/setup", handleCloudSetup).Methods("POST", "OPTIONS") - //r.HandleFunc("/api/v1/execution_cleanup", cleanupExecutions).Methods("GET", "OPTIONS") + r.HandleFunc("/api/v1/getorgs", handleGetOrgs).Methods("GET", "OPTIONS") http.Handle("/", r) } diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 590b016f..e1de6414 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -68,12 +68,13 @@ type ExecutionRequest struct { // Role is just used for feedback for a user type Org struct { - Name string `json:"name"` - Org string `json:"org"` - Users []User `json:"users"` - Id string `json:"id"` - Role string `json:"role"` - CloudSync bool `json:"cloud_sync"` + Name string `json:"name" datastore:"name"` + Id string `json:"id" datastore:"id"` + Org string `json:"org" datastore:"org"` + Users []User `json:"users" datastore:"users"` + Role string `json:"role" datastore:"role"` + Roles []string `json:"roles" datastore:"roles"` + CloudSync bool `json:"cloud_sync" datastore:"CloudSync"` } type AppAuthenticationStorage struct { diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index 6c37c125..6902eb8f 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -101,7 +101,6 @@ const Header = props => { // Should be based on some path const logoCheck = !homePage ? null : null - // Handle top bar or something const loginTextBrowser = !isLoggedIn ?
@@ -184,17 +183,19 @@ const Header = props => { color="primary"> Settings - - - - - + {userdata === undefined || userdata.admin === undefined || userdata.admin === null || !userdata.admin ? null : + + + + + + } {userdata === undefined || userdata.orgs === undefined || userdata.orgs === null || userdata.orgs.length <= 1 ? null :