func init() { var err error me, err = nerdz.NewUser(1) if err != nil { panic(fmt.Sprintf("No error should happen when create existing user, but got: %+v", err)) } other, err = nerdz.NewUser(2) if err != nil { panic(fmt.Sprintf("No error should happen when create existing user, but got: %+v", err)) } blacklisted, _ = nerdz.NewUser(5) withClosedProfile, _ = nerdz.NewUser(7) }
// authorization is the authorization middleware for users. // It checks the access_token in the Authorization header or the access_token query parameter // On success sets "me" = *User (current logged user) and "accessData" = current access data // into the context. Sets even the scopes variable, the sorted slice of scopes in accessData func authorization() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return echo.HandlerFunc(func(c echo.Context) error { var accessToken string auth := c.Request().Header.Get("Authorization") if auth == "" { // Check if there's the parameter access_token in the URL // this makes the bearer authentication with websockets compatible with OAuth2 accessToken = c.QueryParam("access_token") if accessToken == "" { return c.String(http.StatusUnauthorized, "access_token required") } } else { if !strings.HasPrefix(auth, "Bearer ") { return echo.ErrUnauthorized } ss := strings.Split(auth, " ") if len(ss) != 2 { return echo.ErrUnauthorized } accessToken = ss[1] } accessData, err := (&nerdz.OAuth2Storage{}).LoadAccess(accessToken) if err != nil { return c.String(http.StatusUnauthorized, err.Error()) } // fetch current logged user and store it into the context me, err := nerdz.NewUser(accessData.UserData.(uint64)) if err != nil { return c.String(http.StatusInternalServerError, err.Error()) } c.Set("me", me) // store the Access Data into the context c.Set("accessData", accessData) scopes := strings.Split(accessData.Scope, " ") sort.Strings(scopes) // store the sorted Scopes using the full format // eg: if accepted scope is profile:read,write // save 2 entries: profile:read and profile:write // each saved scope is always in the format <name>:<read|,write> var fullScopes []string for _, s := range scopes { //parts[0] = <scope>, parts[1] = <rw> parts := strings.Split(s, ":") rw := strings.Split(parts[1], ",") for _, perm := range rw { fullScopes = append(fullScopes, parts[0]+":"+perm) } } c.Set("scopes", fullScopes) // let next handler handle the context return next(c) }) } }
func TestUnfollowUser(t *testing.T) { other, _ = nerdz.NewUser(3) t.Logf("User(%d) unfollows User(%d)", me.Counter, other.Counter) oldNumFollowers := len(other.NumericFollowers()) if err := me.Unfollow(other); err != nil { t.Error(err) } newNumFollowers := len(other.NumericFollowers()) if newNumFollowers != oldNumFollowers-1 { t.Fatalf("The follower isn't removed from the followers list! (old %d, new %d)", oldNumFollowers, newNumFollowers) } }
func TestFollowUser(t *testing.T) { other, _ = nerdz.NewUser(3) t.Logf("User(%d) follows User(%d)", me.Counter, other.Counter) oldNumFollowers := len(other.NumericFollowers()) if err := me.Follow(other); err != nil { t.Log("The user should correctly follow the other user but: ") t.Error(err) } if len(other.NumericFollowers()) != oldNumFollowers+1 { t.Log("There isn't a new follower for the user!") t.Error("No new follower") } }
func TestPms(t *testing.T) { other, _ = nerdz.NewUser(2) t.Logf("User(%d) -pm-> User(%d)", me.Counter, other.Counter) // build a pm configuration in order to filter results pmConf := nerdz.NewPmConfig().WithDescOrder(true) pmList, err := me.Pms(other.Counter, pmConf) if err != nil { t.Errorf("Error trying to get pms between user(%s) and user(%s) - %v", me.Id(), other.Id(), err) return } t.Log("####### PMS ########") for _, val := range *pmList { t.Logf("%+v", val) } t.Log("####################") pmConf = nerdz.NewPmConfig().WithOffset(2).WithLimit(4) pmListR, errR := me.Pms(other.Counter, pmConf) if errR != nil { t.Errorf("Error trying to get pms between user(%s) and user(%s) - %v", me.Id(), other.Id(), errR) return } t.Log("####### PMS between (2 - 4) ########") for _, val := range *pmListR { t.Logf("%+v", val) } t.Log("####################") }
func TestPms(t *testing.T) { other, _ = nerdz.NewUser(2) t.Logf("User(%d) pm-> User(%d)", me.Counter, other.Counter) pmList, err := me.Pms(other.Counter, nerdz.PmsOptions{}) if err != nil { t.Fatalf("Error trying to get pms between user(%d) and user(%d) - %v", me.ID(), other.ID(), err) return } if len(*pmList) != 9 { t.Fatalf("Expected 9 messages, but got: %d\n", len(*pmList)) } // Delete if err = me.DeleteConversation(other.ID()); err != nil { t.Fatalf("Conversation between me and other should be removed, but got: %s", err.Error()) } pmList, err = me.Pms(other.ID(), nerdz.PmsOptions{}) if len(*pmList) != 0 { t.Fatalf("Conversation between me and other should be removed, but %d messages got instead", len(*pmList)) } }
// User extract "id" from the url parameter, parse it and returns // the User if the "me" (in the context) user is allowed to see it. // Otherwise returns an error func User(userID string, c echo.Context) (*nerdz.User, error) { var id uint64 var e error if id, e = strconv.ParseUint(c.Param(userID), 10, 64); e != nil { c.JSON(http.StatusBadRequest, &Response{ HumanMessage: "Invalid user identifier specified", Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return nil, e } var user *nerdz.User if user, e = nerdz.NewUser(id); e != nil { c.JSON(http.StatusBadRequest, &Response{ HumanMessage: "User does not exists", Message: e.Error(), Status: http.StatusBadRequest, Success: false, }) return nil, e } me := c.Get("me").(*nerdz.User) if !me.CanSee(user) { message := "You can't see the required profile" c.JSON(http.StatusUnauthorized, &Response{ HumanMessage: message, Message: message, Status: http.StatusUnauthorized, Success: false, }) return nil, errors.New(message) } return user, nil }
// Authorize is the action of GET /oauth2/authorize and POST /oauth2/authorize when authentication is required func Authorize() echo.HandlerFunc { return func(c echo.Context) error { resp := oauth.NewResponse() defer resp.Close() if ar := oauth.HandleAuthorizeRequest(resp, c.Request()); ar != nil { if c.QueryParam("authorized") == "" || c.QueryParam("authorized_code") == "" { c.Redirect(http.StatusFound, fmt.Sprintf("%s/oauth2/authorize.php?client_id=%s&response_type=%s&redirect_uri=%s&scope=%s", nerdz.Configuration.NERDZURL().String(), url.QueryEscape(c.QueryParam("client_id")), url.QueryEscape(c.QueryParam("response_type")), url.QueryEscape(c.QueryParam("redirect_uri")), url.QueryEscape(c.QueryParam("scope")))) return nil } else { var e error var userID uint64 if userID, e = strconv.ParseUint(c.QueryParam("authorized"), 10, 64); e != nil { return c.JSON(http.StatusInternalServerError, &rest.Response{ HumanMessage: "Invalid authorized (user id) value", Message: e.Error(), Status: http.StatusInternalServerError, Success: false, }) } var user *nerdz.User if user, e = nerdz.NewUser(userID); e != nil { return c.JSON(http.StatusInternalServerError, &rest.Response{ HumanMessage: "Problem retrieving specified user", Message: e.Error(), Status: http.StatusInternalServerError, Success: false, }) } sha1_sum := fmt.Sprintf("%x", sha1.Sum([]byte(user.Username+user.Password+user.Email))) if sha1_sum != c.QueryParam("authorized_code") { message := "Invalid authorization code" return c.JSON(http.StatusInternalServerError, &rest.Response{ HumanMessage: message, Message: message, Status: http.StatusInternalServerError, Success: false, }) } ar.UserData = user.Counter ar.Authorized = true oauth.FinishAuthorizeRequest(resp, c.Request(), ar) } } if resp.IsError && resp.InternalError != nil { return c.JSON(http.StatusInternalServerError, &rest.Response{ HumanMessage: "Internal Server error", Message: resp.InternalError.Error(), Status: http.StatusInternalServerError, Success: false, }) } return osin.OutputJSON(resp, c.Response(), c.Request()) } }
package examples import ( "fmt" "github.com/nerdzeu/nerdz-api/nerdz" ) var ( // Retrieves all the information about the user with ID 1 // the second parameter, an error, is suppressed user, _ = nerdz.NewUser(1) ) // prints all the friends information func findFriends() { // user.Friends() returns a pointer to an array whose elements are User if friendsList := user.Friends(); friendsList != nil { fmt.Println("#### Friends ######") // Dereference the pointer for _, otherUser := range *friendsList { fmt.Printf("%+v", otherUser) } fmt.Println("##################") } else { fmt.Printf("User(%d) hasn't any friends", user.Counter) } }