Ability to add friends. Also, made a few helper functions.

This commit is contained in:
Howl 2016-04-08 19:05:54 +02:00
parent 7b82c98352
commit 44d12d2493
7 changed files with 116 additions and 26 deletions

View File

@ -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", Method(v1.FriendsGET, db, common.PrivilegeReadConfidential))
gv1.GET("/friends/with/:id", Method(v1.FriendsWithGET, 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 // M E T A
// E T "wow thats so meta" // E T "wow thats so meta"
// T E -- the one who said "wow that's so meta" // T E -- the one who said "wow that's so meta"

View File

@ -22,7 +22,7 @@ func BadgeByIDGET(md common.MethodData) (r common.Response) {
r.Message = "No such badge was found" r.Message = "No such badge was found"
return return
case err != nil: case err != nil:
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -36,7 +36,7 @@ func BadgesGET(md common.MethodData) (r common.Response) {
var badges []badgeData var badges []badgeData
rows, err := md.DB.Query("SELECT id, name, icon FROM badges") rows, err := md.DB.Query("SELECT id, name, icon FROM badges")
if err != nil { if err != nil {
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -45,12 +45,12 @@ func BadgesGET(md common.MethodData) (r common.Response) {
nb := badgeData{} nb := badgeData{}
err = rows.Scan(&nb.ID, &nb.Name, &nb.Icon) err = rows.Scan(&nb.ID, &nb.Name, &nb.Icon)
if err != nil { if err != nil {
md.C.Error(err) md.Err(err)
} }
badges = append(badges, nb) badges = append(badges, nb)
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
md.C.Error(err) md.Err(err)
} }
r.Code = 200 r.Code = 200
r.Data = badges r.Data = badges

View File

@ -2,6 +2,7 @@ package v1
import ( import (
"database/sql" "database/sql"
"encoding/json"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -18,9 +19,9 @@ type friendData struct {
// It retrieves an user's friends, and whether the friendship is mutual or not. // It retrieves an user's friends, and whether the friendship is mutual or not.
func FriendsGET(md common.MethodData) (r common.Response) { func FriendsGET(md common.MethodData) (r common.Response) {
var myFrienders []int 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 { if err != nil {
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -29,13 +30,13 @@ func FriendsGET(md common.MethodData) (r common.Response) {
var i int var i int
err := myFriendersRaw.Scan(&i) err := myFriendersRaw.Scan(&i)
if err != nil { if err != nil {
md.C.Error(err) md.Err(err)
continue continue
} }
myFrienders = append(myFrienders, i) myFrienders = append(myFrienders, i)
} }
if err := myFriendersRaw.Err(); err != nil { if err := myFriendersRaw.Err(); err != nil {
md.C.Error(err) md.Err(err)
} }
// Yes. // Yes.
@ -53,9 +54,9 @@ ON users_relationships.user2=users_stats.id
WHERE users_relationships.user1=? WHERE users_relationships.user1=?
ORDER BY users_relationships.id` 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 { if err != nil {
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -74,7 +75,7 @@ ORDER BY users_relationships.id`
myFriends = append(myFriends, newFriend) myFriends = append(myFriends, newFriend)
} }
if err := results.Err(); err != nil { if err := results.Err(); err != nil {
md.C.Error(err) md.Err(err)
} }
r.Code = 200 r.Code = 200
@ -91,7 +92,7 @@ func friendPuts(md common.MethodData, row *sql.Rows) (user friendData) {
var showcountry bool var showcountry bool
err = row.Scan(&user.ID, &user.Username, &registeredOn, &user.Rank, &latestActivity, &user.UsernameAKA, &badges, &user.Country, &showcountry) err = row.Scan(&user.ID, &user.Username, &registeredOn, &user.Rank, &latestActivity, &user.UsernameAKA, &badges, &user.Country, &showcountry)
if err != nil { if err != nil {
md.C.Error(err) md.Err(err)
return 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. // 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. // 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" user.Country = "XX"
} }
return return
@ -132,12 +133,87 @@ func FriendsWithGET(md common.MethodData) (r common.Response) {
r.Data = d r.Data = d
return 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 { if err != sql.ErrNoRows && err != nil {
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
r.Data = d r.Data = d
return 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
}

View File

@ -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. // 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) { func PingGET(md common.MethodData) (r common.Response) {
r.Code = 200 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))] 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 { } else {
r.Message = surpriseMe() r.Message = surpriseMe()
} }
r.Data = pingData{ r.Data = pingData{
ID: md.User.UserID, ID: md.ID(),
Privileges: int(md.User.Privileges), Privileges: int(md.User.Privileges),
} }
return return

View File

@ -72,7 +72,7 @@ func TokenNewPOST(md common.MethodData) (r common.Response) {
r.Message = "No user with that username/id was found." r.Message = "No user with that username/id was found."
return return
case err != nil: case err != nil:
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -88,7 +88,7 @@ func TokenNewPOST(md common.MethodData) (r common.Response) {
r.Message = "That password doesn't match!" r.Message = "That password doesn't match!"
return return
} }
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -116,14 +116,14 @@ func TokenNewPOST(md common.MethodData) (r common.Response) {
break break
} }
if err != nil { if err != nil {
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
} }
_, err = md.DB.Exec("INSERT INTO tokens(user, privileges, description, token) VALUES (?, ?, ?, ?)", ret.ID, ret.Privileges, data.Description, tokenMD5) _, err = md.DB.Exec("INSERT INTO tokens(user, privileges, description, token) VALUES (?, ?, ?, ?)", ret.ID, ret.Privileges, data.Description, tokenMD5)
if err != nil { if err != nil {
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }

View File

@ -29,7 +29,7 @@ func UserByIDGET(md common.MethodData) (r common.Response) {
var uid int var uid int
uidStr := md.C.Param("id") uidStr := md.C.Param("id")
if uidStr == "self" { if uidStr == "self" {
uid = md.User.UserID uid = md.ID()
} else { } else {
uid, err = strconv.Atoi(uidStr) uid, err = strconv.Atoi(uidStr)
if err != nil { 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!" r.Message = "No such user was found!"
return return
case err != nil: case err != nil:
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -122,7 +122,7 @@ func badgesToArray(badges string) []int {
func genCountry(md common.MethodData, uid int, showCountry bool, country string) string { func genCountry(md common.MethodData, uid int, showCountry bool, country string) string {
// If the user wants to stay anonymous, don't show their country. // 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. // 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 country
} }
return "XX" return "XX"
@ -253,7 +253,7 @@ LIMIT 1
r.Message = "That user could not be found!" r.Message = "That user could not be found!"
return return
case err != nil: case err != nil:
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }
@ -278,7 +278,7 @@ func UserUserpageGET(md common.MethodData) (r common.Response) {
r.Code = 404 r.Code = 404
r.Message = "No user with that user ID!" r.Message = "No user with that user ID!"
case err != nil: case err != nil:
md.C.Error(err) md.Err(err)
r = Err500 r = Err500
return return
} }

View File

@ -13,3 +13,13 @@ type MethodData struct {
RequestData []byte RequestData []byte
C *gin.Context 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
}