Ability to add friends. Also, made a few helper functions.
This commit is contained in:
		| @@ -39,6 +39,10 @@ func Start(conf common.Conf, db *sql.DB) *gin.Engine { | ||||
| 			gv1.GET("/friends", Method(v1.FriendsGET, db, common.PrivilegeReadConfidential)) | ||||
| 			gv1.GET("/friends/with/:id", Method(v1.FriendsWithGET, db, common.PrivilegeReadConfidential)) | ||||
|  | ||||
| 			// Write privilege required | ||||
| 			gv1.POST("/friends/add", Method(v1.FriendsAddPOST, db, common.PrivilegeWrite)) | ||||
| 			gv1.GET("/friends/add/:id", Method(v1.FriendsAddGET, db, common.PrivilegeWrite)) | ||||
|  | ||||
| 			// M E T A | ||||
| 			// E     T    "wow thats so meta" | ||||
| 			// T     E                  -- the one who said "wow that's so meta" | ||||
|   | ||||
| @@ -22,7 +22,7 @@ func BadgeByIDGET(md common.MethodData) (r common.Response) { | ||||
| 		r.Message = "No such badge was found" | ||||
| 		return | ||||
| 	case err != nil: | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -36,7 +36,7 @@ func BadgesGET(md common.MethodData) (r common.Response) { | ||||
| 	var badges []badgeData | ||||
| 	rows, err := md.DB.Query("SELECT id, name, icon FROM badges") | ||||
| 	if err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -45,12 +45,12 @@ func BadgesGET(md common.MethodData) (r common.Response) { | ||||
| 		nb := badgeData{} | ||||
| 		err = rows.Scan(&nb.ID, &nb.Name, &nb.Icon) | ||||
| 		if err != nil { | ||||
| 			md.C.Error(err) | ||||
| 			md.Err(err) | ||||
| 		} | ||||
| 		badges = append(badges, nb) | ||||
| 	} | ||||
| 	if err := rows.Err(); err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 	} | ||||
| 	r.Code = 200 | ||||
| 	r.Data = badges | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package v1 | ||||
|  | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"encoding/json" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| @@ -18,9 +19,9 @@ type friendData struct { | ||||
| // It retrieves an user's friends, and whether the friendship is mutual or not. | ||||
| func FriendsGET(md common.MethodData) (r common.Response) { | ||||
| 	var myFrienders []int | ||||
| 	myFriendersRaw, err := md.DB.Query("SELECT user1 FROM users_relationships WHERE user2 = ?", md.User.UserID) | ||||
| 	myFriendersRaw, err := md.DB.Query("SELECT user1 FROM users_relationships WHERE user2 = ?", md.ID()) | ||||
| 	if err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -29,13 +30,13 @@ func FriendsGET(md common.MethodData) (r common.Response) { | ||||
| 		var i int | ||||
| 		err := myFriendersRaw.Scan(&i) | ||||
| 		if err != nil { | ||||
| 			md.C.Error(err) | ||||
| 			md.Err(err) | ||||
| 			continue | ||||
| 		} | ||||
| 		myFrienders = append(myFrienders, i) | ||||
| 	} | ||||
| 	if err := myFriendersRaw.Err(); err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 	} | ||||
|  | ||||
| 	// Yes. | ||||
| @@ -53,9 +54,9 @@ ON users_relationships.user2=users_stats.id | ||||
| WHERE users_relationships.user1=? | ||||
| ORDER BY users_relationships.id` | ||||
|  | ||||
| 	results, err := md.DB.Query(myFriendsQuery+common.Paginate(md.C.Query("p"), md.C.Query("l")), md.User.UserID) | ||||
| 	results, err := md.DB.Query(myFriendsQuery+common.Paginate(md.C.Query("p"), md.C.Query("l")), md.ID()) | ||||
| 	if err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -74,7 +75,7 @@ ORDER BY users_relationships.id` | ||||
| 		myFriends = append(myFriends, newFriend) | ||||
| 	} | ||||
| 	if err := results.Err(); err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 	} | ||||
|  | ||||
| 	r.Code = 200 | ||||
| @@ -91,7 +92,7 @@ func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) { | ||||
| 	var showcountry bool | ||||
| 	err = row.Scan(&user.ID, &user.Username, ®isteredOn, &user.Rank, &latestActivity, &user.UsernameAKA, &badges, &user.Country, &showcountry) | ||||
| 	if err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -112,7 +113,7 @@ func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) { | ||||
|  | ||||
| 	// If the user wants to stay anonymous, don't show their country. | ||||
| 	// This can be overriden if we have the ReadConfidential privilege and the user we are accessing is the token owner. | ||||
| 	if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.User.UserID)) { | ||||
| 	if !(showcountry || (md.User.Privileges.HasPrivilegeReadConfidential() && user.ID == md.ID())) { | ||||
| 		user.Country = "XX" | ||||
| 	} | ||||
| 	return | ||||
| @@ -132,12 +133,87 @@ func FriendsWithGET(md common.MethodData) (r common.Response) { | ||||
| 		r.Data = d | ||||
| 		return | ||||
| 	} | ||||
| 	err = md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users_relationships WHERE user1 = ? AND user2 = ? LIMIT 1), EXISTS(SELECT 1 FROM users_relationships WHERE user2 = ? AND user1 = ? LIMIT 1)", md.User.UserID, uid, md.User.UserID, uid).Scan(&d.Friends, &d.Mutual) | ||||
| 	err = md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users_relationships WHERE user1 = ? AND user2 = ? LIMIT 1), EXISTS(SELECT 1 FROM users_relationships WHERE user2 = ? AND user1 = ? LIMIT 1)", md.ID(), uid, md.ID(), uid).Scan(&d.Friends, &d.Mutual) | ||||
| 	if err != sql.ErrNoRows && err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| 	r.Data = d | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // FriendsAddGET is the GET version of FriendsAddPOST. | ||||
| func FriendsAddGET(md common.MethodData) common.Response { | ||||
| 	uidS := md.C.Param("id") | ||||
| 	uid, err := strconv.Atoi(uidS) | ||||
| 	if err != nil { | ||||
| 		return common.Response{ | ||||
| 			Code:    400, | ||||
| 			Message: "Nope. That's not a number.", | ||||
| 		} | ||||
| 	} | ||||
| 	return addFriend(md, uid) | ||||
| } | ||||
|  | ||||
| type friendAddPOSTData struct { | ||||
| 	UserID int `json:"user_id"` | ||||
| } | ||||
|  | ||||
| // FriendsAddPOST allows for adding friends. Yup. Easy as that. | ||||
| func FriendsAddPOST(md common.MethodData) (r common.Response) { | ||||
| 	d := friendAddPOSTData{} | ||||
| 	err := json.Unmarshal(md.RequestData, &d) | ||||
| 	if err != nil { | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| 	return addFriend(md, d.UserID) | ||||
| } | ||||
|  | ||||
| func addFriend(md common.MethodData, u int) (r common.Response) { | ||||
| 	if md.ID() == u { | ||||
| 		r.Code = 400 | ||||
| 		r.Message = "Just so you know: you can't add yourself to your friends." | ||||
| 		return | ||||
| 	} | ||||
| 	if !userExists(md, u) { | ||||
| 		r.Code = 404 | ||||
| 		r.Message = "I'd also like to be friends with someone who doesn't even exist (???), however that's NOT POSSIBLE." | ||||
| 		return | ||||
| 	} | ||||
| 	var ( | ||||
| 		relExists bool | ||||
| 		isMutual  bool | ||||
| 	) | ||||
| 	err := md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users_relationships WHERE user1 = ? AND user2 = ?), EXISTS(SELECT 1 FROM users_relationships WHERE user2 = ? AND user1 = ?)", md.ID(), u, md.ID(), u).Scan(&relExists, &isMutual) | ||||
| 	if err != nil && err != sql.ErrNoRows { | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| 	if !relExists { | ||||
| 		_, err := md.DB.Exec("INSERT INTO users_relationships(user1, user2) VALUES (?, ?)", md.User.UserID, u) | ||||
| 		if err != nil { | ||||
| 			md.Err(err) | ||||
| 			r = Err500 | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	r.Code = 200 | ||||
| 	r.Data = friendsWithData{ | ||||
| 		Friends: relExists, | ||||
| 		Mutual:  isMutual, | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // userExists makes sure an user exists. | ||||
| func userExists(md common.MethodData, u int) (r bool) { | ||||
| 	err := md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE id = ?)", u).Scan(&r) | ||||
| 	if err != nil && err != sql.ErrNoRows { | ||||
| 		md.Err(err) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|   | ||||
| @@ -90,13 +90,13 @@ type pingData struct { | ||||
| // PingGET is a message to check with the API that we are logged in, and know what are our privileges. | ||||
| func PingGET(md common.MethodData) (r common.Response) { | ||||
| 	r.Code = 200 | ||||
| 	if md.User.UserID == 0 { | ||||
| 	if md.ID() == 0 { | ||||
| 		r.Message = "You have not given us a token, so we don't know who you are! But you can still login with /api/v1/login " + kaomojis[rn.Intn(len(kaomojis))] | ||||
| 	} else { | ||||
| 		r.Message = surpriseMe() | ||||
| 	} | ||||
| 	r.Data = pingData{ | ||||
| 		ID:         md.User.UserID, | ||||
| 		ID:         md.ID(), | ||||
| 		Privileges: int(md.User.Privileges), | ||||
| 	} | ||||
| 	return | ||||
|   | ||||
| @@ -72,7 +72,7 @@ func TokenNewPOST(md common.MethodData) (r common.Response) { | ||||
| 		r.Message = "No user with that username/id was found." | ||||
| 		return | ||||
| 	case err != nil: | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -88,7 +88,7 @@ func TokenNewPOST(md common.MethodData) (r common.Response) { | ||||
| 			r.Message = "That password doesn't match!" | ||||
| 			return | ||||
| 		} | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -116,14 +116,14 @@ func TokenNewPOST(md common.MethodData) (r common.Response) { | ||||
| 			break | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			md.C.Error(err) | ||||
| 			md.Err(err) | ||||
| 			r = Err500 | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	_, err = md.DB.Exec("INSERT INTO tokens(user, privileges, description, token) VALUES (?, ?, ?, ?)", ret.ID, ret.Privileges, data.Description, tokenMD5) | ||||
| 	if err != nil { | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -29,7 +29,7 @@ func UserByIDGET(md common.MethodData) (r common.Response) { | ||||
| 	var uid int | ||||
| 	uidStr := md.C.Param("id") | ||||
| 	if uidStr == "self" { | ||||
| 		uid = md.User.UserID | ||||
| 		uid = md.ID() | ||||
| 	} else { | ||||
| 		uid, err = strconv.Atoi(uidStr) | ||||
| 		if err != nil { | ||||
| @@ -86,7 +86,7 @@ func userPuts(md common.MethodData, row *sql.Row) (r common.Response) { | ||||
| 		r.Message = "No such user was found!" | ||||
| 		return | ||||
| 	case err != nil: | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -122,7 +122,7 @@ func badgesToArray(badges string) []int { | ||||
| func genCountry(md common.MethodData, uid int, showCountry bool, country string) string { | ||||
| 	// If the user wants to stay anonymous, don't show their country. | ||||
| 	// This can be overriden if we have the ReadConfidential privilege and the user we are accessing is the token owner. | ||||
| 	if showCountry || (md.User.Privileges.HasPrivilegeReadConfidential() && uid == md.User.UserID) { | ||||
| 	if showCountry || (md.User.Privileges.HasPrivilegeReadConfidential() && uid == md.ID()) { | ||||
| 		return country | ||||
| 	} | ||||
| 	return "XX" | ||||
| @@ -253,7 +253,7 @@ LIMIT 1 | ||||
| 		r.Message = "That user could not be found!" | ||||
| 		return | ||||
| 	case err != nil: | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
| @@ -278,7 +278,7 @@ func UserUserpageGET(md common.MethodData) (r common.Response) { | ||||
| 		r.Code = 404 | ||||
| 		r.Message = "No user with that user ID!" | ||||
| 	case err != nil: | ||||
| 		md.C.Error(err) | ||||
| 		md.Err(err) | ||||
| 		r = Err500 | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -13,3 +13,13 @@ type MethodData struct { | ||||
| 	RequestData []byte | ||||
| 	C           *gin.Context | ||||
| } | ||||
|  | ||||
| // Err logs an error into gin. | ||||
| func (md MethodData) Err(err error) { | ||||
| 	md.C.Error(err) | ||||
| } | ||||
|  | ||||
| // ID retrieves the Token's owner user ID. | ||||
| func (md MethodData) ID() int { | ||||
| 	return md.User.UserID | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user