mirror of
https://github.com/notherealmarco/WASAPhoto.git
synced 2025-03-14 14:16:15 +01:00
Add stream search, offset & limit, improved bans
This commit is contained in:
parent
72f11a2b15
commit
963e392cea
14 changed files with 298 additions and 65 deletions
|
@ -11,6 +11,8 @@ func (rt *_router) Handler() http.Handler {
|
||||||
|
|
||||||
rt.router.PUT("/users/:user_id/username", rt.wrap(rt.UpdateUsername))
|
rt.router.PUT("/users/:user_id/username", rt.wrap(rt.UpdateUsername))
|
||||||
|
|
||||||
|
rt.router.GET("/users", rt.wrap(rt.GetSearchUsers))
|
||||||
|
|
||||||
rt.router.GET("/users/:user_id/followers", rt.wrap(rt.GetFollowersFollowing))
|
rt.router.GET("/users/:user_id/followers", rt.wrap(rt.GetFollowersFollowing))
|
||||||
rt.router.PUT("/users/:user_id/followers/:follower_uid", rt.wrap(rt.PutFollow))
|
rt.router.PUT("/users/:user_id/followers/:follower_uid", rt.wrap(rt.PutFollow))
|
||||||
rt.router.DELETE("/users/:user_id/followers/:follower_uid", rt.wrap(rt.DeleteFollow))
|
rt.router.DELETE("/users/:user_id/followers/:follower_uid", rt.wrap(rt.DeleteFollow))
|
||||||
|
@ -33,6 +35,8 @@ func (rt *_router) Handler() http.Handler {
|
||||||
|
|
||||||
rt.router.GET("/users/:user_id", rt.wrap(rt.GetUserProfile))
|
rt.router.GET("/users/:user_id", rt.wrap(rt.GetUserProfile))
|
||||||
|
|
||||||
|
rt.router.GET("/stream", rt.wrap(rt.GetUserStream)) //todo: why not "/users/:user_id/stream"?
|
||||||
|
|
||||||
rt.router.GET("/", rt.getHelloWorld)
|
rt.router.GET("/", rt.getHelloWorld)
|
||||||
rt.router.GET("/context", rt.wrap(rt.getContextReply))
|
rt.router.GET("/context", rt.wrap(rt.getContextReply))
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ func (rt *_router) GetComments(w http.ResponseWriter, r *http.Request, ps httpro
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the user's comments
|
// get the user's comments
|
||||||
success, comments, err := rt.db.GetComments(uid, photo_id)
|
success, comments, err := rt.db.GetComments(uid, photo_id, ctx.Auth.GetUserID())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helpers.SendInternalError(err, "Database error: GetComments", w, rt.baseLogger)
|
helpers.SendInternalError(err, "Database error: GetComments", w, rt.baseLogger)
|
||||||
|
|
|
@ -28,10 +28,10 @@ func (rt *_router) GetFollowersFollowing(w http.ResponseWriter, r *http.Request,
|
||||||
// Check if client is asking for followers or following
|
// Check if client is asking for followers or following
|
||||||
if strings.HasSuffix(r.URL.Path, "/followers") {
|
if strings.HasSuffix(r.URL.Path, "/followers") {
|
||||||
// Get the followers from the database
|
// Get the followers from the database
|
||||||
status, users, err = rt.db.GetUserFollowers(uid)
|
status, users, err = rt.db.GetUserFollowers(uid, ctx.Auth.GetUserID())
|
||||||
} else {
|
} else {
|
||||||
// Get the following users from the database
|
// Get the following users from the database
|
||||||
status, users, err = rt.db.GetUserFollowing(uid)
|
status, users, err = rt.db.GetUserFollowing(uid, ctx.Auth.GetUserID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a 500 response if there was an error
|
// Send a 500 response if there was an error
|
||||||
|
|
48
service/api/get-stream.go
Normal file
48
service/api/get-stream.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/api/authorization"
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/api/helpers"
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/api/reqcontext"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rt *_router) GetUserStream(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) {
|
||||||
|
|
||||||
|
// We must know who is requesting the stream
|
||||||
|
if !authorization.SendErrorIfNotLoggedIn(ctx.Auth.Authorized, rt.db, w, rt.baseLogger) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user id, probably this should be changed as it's not really REST
|
||||||
|
uid := ctx.Auth.GetUserID()
|
||||||
|
|
||||||
|
// Get start index and limit, or their default values
|
||||||
|
start_index, limit, err := helpers.GetLimits(r.URL.Query())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.SendBadRequest(w, "Invalid start_index or limit value", rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the stream
|
||||||
|
stream, err := rt.db.GetUserStream(uid, start_index, limit)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.SendInternalError(err, "Database error: GetUserProfile", w, rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the stream in json format
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
err = json.NewEncoder(w).Encode(stream)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.SendInternalError(err, "Error encoding json", w, rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
33
service/api/helpers/get-limits.go
Normal file
33
service/api/helpers/get-limits.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DEFAULT_LIMIT = 10 // todo: move to config
|
||||||
|
DEFAULT_OFFSET = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetLimits(query url.Values) (int, int, error) {
|
||||||
|
|
||||||
|
limit := DEFAULT_LIMIT
|
||||||
|
start_index := DEFAULT_OFFSET
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if query.Get("limit") != "" {
|
||||||
|
limit, err = strconv.Atoi(query.Get("limit"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Get("start_index") != "" {
|
||||||
|
start_index, err = strconv.Atoi(query.Get("start_index"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return start_index, limit, nil
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ func (rt *_router) GetLikes(w http.ResponseWriter, r *http.Request, ps httproute
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the user's likes
|
// get the user's likes
|
||||||
success, likes, err := rt.db.GetPhotoLikes(uid, photo_id)
|
success, likes, err := rt.db.GetPhotoLikes(uid, photo_id, ctx.Auth.GetUserID())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helpers.SendInternalError(err, "Database error: GetLikes", w, rt.baseLogger)
|
helpers.SendInternalError(err, "Database error: GetLikes", w, rt.baseLogger)
|
||||||
|
|
53
service/api/search.go
Normal file
53
service/api/search.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/api/authorization"
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/api/helpers"
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/api/reqcontext"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rt *_router) GetSearchUsers(w http.ResponseWriter, r *http.Request, ps httprouter.Params, ctx reqcontext.RequestContext) {
|
||||||
|
|
||||||
|
// We require user to be authenticated
|
||||||
|
if !authorization.SendErrorIfNotLoggedIn(ctx.Auth.Authorized, rt.db, w, rt.baseLogger) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get search query
|
||||||
|
query := r.URL.Query().Get("query")
|
||||||
|
|
||||||
|
if query == "" {
|
||||||
|
helpers.SendBadRequest(w, "Missing query parameter", rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get start index and limit, or their default values
|
||||||
|
start_index, limit, err := helpers.GetLimits(r.URL.Query())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.SendBadRequest(w, "Invalid start_index or limit value", rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get search results
|
||||||
|
results, err := rt.db.SearchByName(query, ctx.Auth.GetUserID(), start_index, limit)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.SendInternalError(err, "Database error: SearchByName", w, rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the results in json format
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
err = json.NewEncoder(w).Encode(results)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
helpers.SendInternalError(err, "Error encoding json", w, rt.baseLogger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,10 +44,12 @@ type AppDatabase interface {
|
||||||
UserExists(uid string) (bool, error)
|
UserExists(uid string) (bool, error)
|
||||||
GetUserID(name string) (string, error)
|
GetUserID(name string) (string, error)
|
||||||
|
|
||||||
|
SearchByName(name string, requesting_uid string, start_index int, limit int) (*[]structures.UIDName, error)
|
||||||
|
|
||||||
UpdateUsername(uid, name string) error
|
UpdateUsername(uid, name string) error
|
||||||
|
|
||||||
GetUserFollowers(uid string) (QueryResult, *[]structures.UIDName, error) // todo: maybe use a pointer to a slice?
|
GetUserFollowers(uid string, requesting_uid string) (QueryResult, *[]structures.UIDName, error) // todo: maybe use a pointer to a slice?
|
||||||
GetUserFollowing(uid string) (QueryResult, *[]structures.UIDName, error)
|
GetUserFollowing(uid string, requesting_uid string) (QueryResult, *[]structures.UIDName, error)
|
||||||
FollowUser(uid string, follow string) (QueryResult, error)
|
FollowUser(uid string, follow string) (QueryResult, error)
|
||||||
UnfollowUser(uid string, unfollow string) (QueryResult, error)
|
UnfollowUser(uid string, unfollow string) (QueryResult, error)
|
||||||
|
|
||||||
|
@ -58,13 +60,14 @@ type AppDatabase interface {
|
||||||
PostPhoto(uid string) (DBTransaction, int64, error)
|
PostPhoto(uid string) (DBTransaction, int64, error)
|
||||||
DeletePhoto(uid string, photo int64) (bool, error)
|
DeletePhoto(uid string, photo int64) (bool, error)
|
||||||
|
|
||||||
GetPhotoLikes(uid string, photo int64) (QueryResult, *[]structures.UIDName, error)
|
GetPhotoLikes(uid string, photo int64, requesting_uid string) (QueryResult, *[]structures.UIDName, error)
|
||||||
LikePhoto(uid string, photo int64, liker_uid string) (QueryResult, error)
|
LikePhoto(uid string, photo int64, liker_uid string) (QueryResult, error)
|
||||||
UnlikePhoto(uid string, photo int64, liker_uid string) (QueryResult, error)
|
UnlikePhoto(uid string, photo int64, liker_uid string) (QueryResult, error)
|
||||||
|
|
||||||
GetUserProfile(uid string) (QueryResult, *structures.UserProfile, error)
|
GetUserProfile(uid string) (QueryResult, *structures.UserProfile, error)
|
||||||
|
GetUserStream(uid string, start_index int, limit int) (*[]structures.Photo, error)
|
||||||
|
|
||||||
GetComments(uid string, photo_id int64) (QueryResult, *[]structures.Comment, error)
|
GetComments(uid string, photo_id int64, requesting_uid string) (QueryResult, *[]structures.Comment, error)
|
||||||
PostComment(uid string, photo_id int64, comment_user string, comment string) (QueryResult, error)
|
PostComment(uid string, photo_id int64, comment_user string, comment string) (QueryResult, error)
|
||||||
DeleteComment(uid string, photo_id int64, comment_id int64) (QueryResult, error)
|
DeleteComment(uid string, photo_id int64, comment_id int64) (QueryResult, error)
|
||||||
GetCommentOwner(uid string, photo_id int64, comment_id int64) (QueryResult, string, error)
|
GetCommentOwner(uid string, photo_id int64, comment_id int64) (QueryResult, string, error)
|
||||||
|
|
|
@ -81,7 +81,7 @@ func (db *appdbimpl) DeleteComment(uid string, photo_id int64, comment_id int64)
|
||||||
return SUCCESS, nil
|
return SUCCESS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *appdbimpl) GetComments(uid string, photo_id int64) (QueryResult, *[]structures.Comment, error) {
|
func (db *appdbimpl) GetComments(uid string, photo_id int64, requesting_uid string, start_index int, limit int) (QueryResult, *[]structures.Comment, error) {
|
||||||
|
|
||||||
// Check if the photo exists, as it exist but have no comments
|
// Check if the photo exists, as it exist but have no comments
|
||||||
exists, err := db.photoExists(uid, photo_id)
|
exists, err := db.photoExists(uid, photo_id)
|
||||||
|
@ -89,7 +89,15 @@ func (db *appdbimpl) GetComments(uid string, photo_id int64) (QueryResult, *[]st
|
||||||
return ERR_NOT_FOUND, nil, err
|
return ERR_NOT_FOUND, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := db.c.Query(`SELECT "id", "user", "comment", "date" FROM "comments" WHERE "photo" = ?`, photo_id)
|
rows, err := db.c.Query(`SELECT "c"."id", "c"."user", "c"."comment", "c"."date" FROM "comments" AS "c"
|
||||||
|
WHERE "c"."photo" = ?
|
||||||
|
AND "c"."user" NOT IN (
|
||||||
|
SELECT "bans"."user" FROM "bans"
|
||||||
|
WHERE "bans"."user" = ?
|
||||||
|
AND "bans"."ban" = "c"."user"
|
||||||
|
)
|
||||||
|
OFFSET ?
|
||||||
|
LIMIT ?`, photo_id, requesting_uid, start_index, limit)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ERR_INTERNAL, nil, err
|
return ERR_INTERNAL, nil, err
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get the list of users who liked a photo
|
// Get the list of users who liked a photo
|
||||||
func (db *appdbimpl) GetPhotoLikes(uid string, photo int64) (QueryResult, *[]structures.UIDName, error) {
|
func (db *appdbimpl) GetPhotoLikes(uid string, photo int64, requesting_uid string, start_index int, limit int) (QueryResult, *[]structures.UIDName, error) {
|
||||||
|
|
||||||
// Check if the photo exists, as it could exist but have no likes
|
// Check if the photo exists, as it could exist but have no likes
|
||||||
exists, err := db.photoExists(uid, photo)
|
exists, err := db.photoExists(uid, photo)
|
||||||
|
@ -20,7 +20,14 @@ func (db *appdbimpl) GetPhotoLikes(uid string, photo int64) (QueryResult, *[]str
|
||||||
|
|
||||||
rows, err := db.c.Query(`SELECT "users"."uid", "users"."name" FROM "likes", "users"
|
rows, err := db.c.Query(`SELECT "users"."uid", "users"."name" FROM "likes", "users"
|
||||||
WHERE "likes"."photo_id" = ?
|
WHERE "likes"."photo_id" = ?
|
||||||
AND "likes"."user" = "users"."uid"`, photo)
|
AND "likes"."user" NOT IN (
|
||||||
|
SELECT "bans"."user" FROM "bans"
|
||||||
|
WHERE "bans"."user" = ?
|
||||||
|
AND "bans"."ban" = "likes"."user"
|
||||||
|
)
|
||||||
|
AND "likes"."user" = "users"."uid"
|
||||||
|
OFFSET ?
|
||||||
|
LIMIT ?`, photo, requesting_uid, start_index, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ERR_INTERNAL, nil, err
|
return ERR_INTERNAL, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/notherealmarco/WASAPhoto/service/structures"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Post a new photo
|
// Post a new photo
|
||||||
|
@ -44,41 +42,6 @@ func (db *appdbimpl) DeletePhoto(uid string, photo int64) (bool, error) {
|
||||||
return rows > 0, nil
|
return rows > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *appdbimpl) getUserPhotos(uid string) (*[]structures.Photo, error) {
|
|
||||||
|
|
||||||
// Get photos
|
|
||||||
rows, err := db.c.Query(`SELECT "p"."user", "p"."id", "p"."date",
|
|
||||||
(
|
|
||||||
SELECT COUNT(*) AS "likes" FROM "likes" AS "l"
|
|
||||||
WHERE "l"."photo_id" = "p"."id"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SELECT COUNT(*) AS "comments" FROM "comments" AS "c"
|
|
||||||
WHERE "c"."photo" = "p"."id"
|
|
||||||
)
|
|
||||||
FROM "photos" AS "p"
|
|
||||||
WHERE "p"."user" = ?`, uid)
|
|
||||||
if err != nil {
|
|
||||||
// Return the error
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
photos := make([]structures.Photo, 0)
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
// If there is a next row, we create an instance of Photo and add it to the slice
|
|
||||||
var photo structures.Photo
|
|
||||||
err = rows.Scan(&photo.UID, &photo.ID, &photo.Date, &photo.Likes, &photo.Comments)
|
|
||||||
if err != nil {
|
|
||||||
// Return the error
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
photos = append(photos, photo)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &photos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a given photo owned by a given user exists
|
// Check if a given photo owned by a given user exists
|
||||||
func (db *appdbimpl) photoExists(uid string, photo int64) (bool, error) {
|
func (db *appdbimpl) photoExists(uid string, photo int64) (bool, error) {
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"github.com/notherealmarco/WASAPhoto/service/structures"
|
"github.com/notherealmarco/WASAPhoto/service/structures"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//this should be changed, but we need to change OpenAPI first
|
||||||
|
|
||||||
// Get user profile, including username, followers, following, and photos
|
// Get user profile, including username, followers, following, and photos
|
||||||
func (db *appdbimpl) GetUserProfile(uid string) (QueryResult, *structures.UserProfile, error) {
|
func (db *appdbimpl) GetUserProfile(uid string) (QueryResult, *structures.UserProfile, error) {
|
||||||
// Get user info
|
// Get user info
|
||||||
|
@ -43,21 +45,46 @@ func (db *appdbimpl) GetUserProfile(uid string) (QueryResult, *structures.UserPr
|
||||||
return ERR_INTERNAL, nil, err
|
return ERR_INTERNAL, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert []Photo to []UserPhoto
|
|
||||||
user_photos := make([]structures.UserPhoto, 0)
|
|
||||||
for _, photo := range *photos {
|
|
||||||
user_photos = append(user_photos, structures.UserPhoto{
|
|
||||||
ID: photo.ID,
|
|
||||||
Likes: photo.Likes,
|
|
||||||
Comments: photo.Comments,
|
|
||||||
Date: photo.Date,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCESS, &structures.UserProfile{
|
return SUCCESS, &structures.UserProfile{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
Name: name,
|
Name: name,
|
||||||
Following: following,
|
Following: following,
|
||||||
Followers: followers,
|
Followers: followers,
|
||||||
Photos: &user_photos}, nil
|
Photos: photos,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *appdbimpl) getUserPhotos(uid string) (*[]structures.UserPhoto, error) {
|
||||||
|
|
||||||
|
// Get photos
|
||||||
|
rows, err := db.c.Query(`SELECT "p"."id", "p"."date",
|
||||||
|
(
|
||||||
|
SELECT COUNT(*) AS "likes" FROM "likes" AS "l"
|
||||||
|
WHERE "l"."photo_id" = "p"."id"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
SELECT COUNT(*) AS "comments" FROM "comments" AS "c"
|
||||||
|
WHERE "c"."photo" = "p"."id"
|
||||||
|
)
|
||||||
|
FROM "photos" AS "p"
|
||||||
|
WHERE "p"."user" = ?`, uid)
|
||||||
|
if err != nil {
|
||||||
|
// Return the error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
photos := make([]structures.UserPhoto, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
// If there is a next row, we create an instance of Photo and add it to the slice
|
||||||
|
var photo structures.UserPhoto
|
||||||
|
err = rows.Scan(&photo.ID, &photo.Date, &photo.Likes, &photo.Comments)
|
||||||
|
if err != nil {
|
||||||
|
// Return the error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
photos = append(photos, photo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &photos, nil
|
||||||
}
|
}
|
||||||
|
|
50
service/database/db-stream.go
Normal file
50
service/database/db-stream.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/notherealmarco/WASAPhoto/service/structures"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get user stream
|
||||||
|
// todo implement stidx + offset
|
||||||
|
func (db *appdbimpl) GetUserStream(uid string, start_index int, limit int) (*[]structures.Photo, error) {
|
||||||
|
|
||||||
|
// Get photos
|
||||||
|
rows, err := db.c.Query(`SELECT "p"."user", "p"."id", "p"."date",
|
||||||
|
(
|
||||||
|
SELECT COUNT(*) AS "likes" FROM "likes" AS "l"
|
||||||
|
WHERE "l"."photo_id" = "p"."id"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
SELECT COUNT(*) AS "comments" FROM "comments" AS "c"
|
||||||
|
WHERE "c"."photo" = "p"."id"
|
||||||
|
)
|
||||||
|
FROM "photos" AS "p"
|
||||||
|
WHERE "p"."user" IN (
|
||||||
|
SELECT "followed" FROM "follows" WHERE "follower" = ?
|
||||||
|
)
|
||||||
|
AND "p"."user" NOT IN (
|
||||||
|
SELECT "user" FROM "bans" WHERE "ban" = ?
|
||||||
|
)
|
||||||
|
ORDER BY "p"."date" DESC
|
||||||
|
OFFSET ?
|
||||||
|
LIMIT ?`, uid, uid, start_index, limit)
|
||||||
|
if err != nil {
|
||||||
|
// Return the error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
photos := make([]structures.Photo, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
// If there is a next row, we create an instance of Photo and add it to the slice
|
||||||
|
var photo structures.Photo
|
||||||
|
err = rows.Scan(&photo.UID, &photo.ID, &photo.Date, &photo.Likes, &photo.Comments)
|
||||||
|
if err != nil {
|
||||||
|
// Return the error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
photos = append(photos, photo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &photos, nil
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ func (db *appdbimpl) UpdateUsername(uid string, name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user followers
|
// Get user followers
|
||||||
func (db *appdbimpl) GetUserFollowers(uid string) (QueryResult, *[]structures.UIDName, error) {
|
func (db *appdbimpl) GetUserFollowers(uid string, requesting_uid string) (QueryResult, *[]structures.UIDName, error) {
|
||||||
|
|
||||||
// user may exist but have no followers
|
// user may exist but have no followers
|
||||||
exists, err := db.UserExists(uid)
|
exists, err := db.UserExists(uid)
|
||||||
|
@ -63,7 +63,14 @@ func (db *appdbimpl) GetUserFollowers(uid string) (QueryResult, *[]structures.UI
|
||||||
|
|
||||||
rows, err := db.c.Query(`SELECT "follower", "user"."name" FROM "follows", "users"
|
rows, err := db.c.Query(`SELECT "follower", "user"."name" FROM "follows", "users"
|
||||||
WHERE "follows"."follower" = "users"."uid"
|
WHERE "follows"."follower" = "users"."uid"
|
||||||
AND "followed" = ?`, uid)
|
|
||||||
|
AND "follows"."follower" NOT IN (
|
||||||
|
SELECT "bans"."user" FROM "bans"
|
||||||
|
WHERE "bans"."user" = ?
|
||||||
|
AND "bans"."ban" = "follows"."follower"
|
||||||
|
)
|
||||||
|
|
||||||
|
AND "followed" = ?`, uid, requesting_uid)
|
||||||
|
|
||||||
followers, err := db.uidNameQuery(rows, err)
|
followers, err := db.uidNameQuery(rows, err)
|
||||||
|
|
||||||
|
@ -75,7 +82,7 @@ func (db *appdbimpl) GetUserFollowers(uid string) (QueryResult, *[]structures.UI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user following
|
// Get user following
|
||||||
func (db *appdbimpl) GetUserFollowing(uid string) (QueryResult, *[]structures.UIDName, error) {
|
func (db *appdbimpl) GetUserFollowing(uid string, requesting_uid string) (QueryResult, *[]structures.UIDName, error) {
|
||||||
|
|
||||||
// user may exist but have no followers
|
// user may exist but have no followers
|
||||||
exists, err := db.UserExists(uid)
|
exists, err := db.UserExists(uid)
|
||||||
|
@ -90,7 +97,14 @@ func (db *appdbimpl) GetUserFollowing(uid string) (QueryResult, *[]structures.UI
|
||||||
|
|
||||||
rows, err := db.c.Query(`SELECT "followed", "user"."name" FROM "follows", "users"
|
rows, err := db.c.Query(`SELECT "followed", "user"."name" FROM "follows", "users"
|
||||||
WHERE "follows"."followed" = "users"."uid"
|
WHERE "follows"."followed" = "users"."uid"
|
||||||
AND "follower" = ?`, uid)
|
|
||||||
|
AND "follows"."followed" NOT IN (
|
||||||
|
SELECT "bans"."user" FROM "bans"
|
||||||
|
WHERE "bans"."user" = ?
|
||||||
|
AND "bans"."ban" = "follows"."followed"
|
||||||
|
)
|
||||||
|
|
||||||
|
AND "follower" = ?`, uid, requesting_uid)
|
||||||
|
|
||||||
following, err := db.uidNameQuery(rows, err)
|
following, err := db.uidNameQuery(rows, err)
|
||||||
|
|
||||||
|
@ -216,3 +230,26 @@ func (db *appdbimpl) IsBanned(uid string, banner string) (bool, error) {
|
||||||
|
|
||||||
return cnt > 0, nil
|
return cnt > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search by name
|
||||||
|
func (db *appdbimpl) SearchByName(name string, requesting_uid string, start_index int, limit int) (*[]structures.UIDName, error) {
|
||||||
|
|
||||||
|
rows, err := db.c.Query(`SELECT "uid", "name" FROM "users"
|
||||||
|
WHERE "name" LIKE ?
|
||||||
|
|
||||||
|
AND "uid" NOT IN (
|
||||||
|
SELECT "bans"."user" FROM "bans"
|
||||||
|
WHERE "bans"."user" = "users"."uid"
|
||||||
|
AND "bans"."ban" = ?
|
||||||
|
)
|
||||||
|
OFFSET ?
|
||||||
|
LIMIT ?`, name, requesting_uid, start_index, limit)
|
||||||
|
|
||||||
|
users, err := db.uidNameQuery(rows, err)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue