Skip to content

Commit

Permalink
feat: user like is now nested on user document
Browse files Browse the repository at this point in the history
  • Loading branch information
ayoubfaouzi committed Sep 28, 2024
1 parent 7aa6d2c commit 5a39f67
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 84 deletions.
6 changes: 6 additions & 0 deletions db/action-like.n1ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* N1QL query to prepend a liked file from a user's likes. */

UPDATE `bucket_name`
USE KEYS $user
SET likes = ARRAY_PREPEND({"sha256": $sha256, "ts": $ts}, likes)
WHERE NOT ANY item IN likes SATISFIES item.sha256 = $sha256 END;
7 changes: 7 additions & 0 deletions db/action-unlike.n1ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* N1QL query to remove a liked file from a user's likes. */

UPDATE `bucket_name`
USE KEYS $user
SET likes = ARRAY like_item FOR like_item IN likes
WHEN like_item.sha256 != $sha256 END
WHERE ANY like_item IN likes SATISFIES like_item.sha256 = $sha256 END;
20 changes: 8 additions & 12 deletions db/ano-user-likes.n1ql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* N1QL query to retrieve likes for an anonymous user. */
SELECT
{
"id": META(act).id,
"date": act.timestamp,
"id": UUID(),
"date": l.ts,
"liked": FALSE,
"file": {
"hash": f.sha256,
Expand All @@ -23,19 +23,15 @@ SELECT
FROM
(
SELECT
u.*
userLikes.*
FROM
`bucket_name` s
USE KEYS
$user
JOIN `bucket_name` u ON KEYS s.`likes`
) AS f
LEFT JOIN `bucket_name` act ON act.target = f.sha256
WHERE
act.`type` = "activity"
AND act.kind = "like"
AND LOWER(act.username) = $user
ORDER BY
act.timestamp DESC OFFSET $offset
UNNEST s.likes AS userLikes
) AS l
LEFT JOIN `bucket_name` f ON f.sha256 = l.sha256
WHERE f.`type` = "file"
OFFSET $offset
LIMIT
$limit
27 changes: 11 additions & 16 deletions db/user-likes.n1ql
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

SELECT
{
"id": META(act).id,
"date": act.timestamp,
"id": UUID(),
"date": l.ts,
"liked": ARRAY_BINARY_SEARCH(
ARRAY_SORT(
(
SELECT
RAW likes
SELECT RAW
ARRAY like_item.sha256 FOR like_item IN u.`likes` END AS sha256_array
FROM
`bucket_name`
`bucket_name` u
USE KEYS
$loggedInUser
) [0]
)[0]
),
f.sha256
) >= 0,
Expand All @@ -36,19 +36,14 @@ SELECT
FROM
(
SELECT
u.*
userLikes.*
FROM
`bucket_name` s
USE KEYS
$user
JOIN `bucket_name` u ON KEYS s.`likes`
) AS f
LEFT JOIN `bucket_name` act ON act.target = f.sha256
WHERE
act.`type` = "activity"
AND act.kind = "like"
AND LOWER(act.username) = $user
ORDER BY
act.timestamp DESC OFFSET $offset
UNNEST s.likes AS userLikes
) AS l
LEFT JOIN `bucket_name` f ON f.sha256 = l.sha256
WHERE f.`type` = "file"OFFSET $offset
LIMIT
$limit
4 changes: 4 additions & 0 deletions internal/db/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,13 @@ const (
UserFollowing
UserLikes
UserSubmissions
ActionLike
ActionUnlike
)

var fileQueryMap = map[string]n1qlQuery{
"action-like.n1ql": ActionLike,
"action-unlike.n1ql": ActionUnlike,
"ano-user-activities.n1ql": AnoUserActivities,
"ano-user-comments.n1ql": AnoUserComments,
"ano-user-followers.n1ql": AnoUserFollowers,
Expand Down
2 changes: 1 addition & 1 deletion internal/entity/comment.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 Saferwall. All rights reserved.
// Copyright 2018 Saferwall. All rights reserved.
// Use of this source code is governed by Apache v2 license
// license that can be found in the LICENSE file.

Expand Down
2 changes: 1 addition & 1 deletion internal/entity/id.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 Saferwall. All rights reserved.
// Copyright 2018 Saferwall. All rights reserved.
// Use of this source code is governed by Apache v2 license
// license that can be found in the LICENSE file.

Expand Down
47 changes: 26 additions & 21 deletions internal/entity/user.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,38 @@
// Copyright 2021 Saferwall. All rights reserved.
// Copyright 2018 Saferwall. All rights reserved.
// Use of this source code is governed by Apache v2 license
// license that can be found in the LICENSE file.

package entity

import "strings"

// UserLike represents likes files by a user.
type UserLike struct {
SHA256 string `json:"sha256"`
Timestamp int64 `json:"ts"`
}

// User represents a user.
type User struct {
Type string `json:"type"`
Email string `json:"email,omitempty"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
FullName string `json:"name"`
Location string `json:"location"`
URL string `json:"url"`
Bio string `json:"bio"`
Confirmed bool `json:"confirmed"`
MemberSince int64 `json:"member_since"`
LastSeen int64 `json:"last_seen"`
Admin bool `json:"admin"`
Following []string `json:"following"`
FollowingCount int `json:"following_count"`
Followers []string `json:"followers"`
FollowersCount int `json:"followers_count"`
Likes []string `json:"likes"`
LikesCount int `json:"likes_count"`
SubmissionsCount int `json:"submissions_count"`
CommentsCount int `json:"comments_count"`
Type string `json:"type"`
Email string `json:"email,omitempty"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
FullName string `json:"name"`
Location string `json:"location"`
URL string `json:"url"`
Bio string `json:"bio"`
Confirmed bool `json:"confirmed"`
MemberSince int64 `json:"member_since"`
LastSeen int64 `json:"last_seen"`
Admin bool `json:"admin"`
Following []string `json:"following"`
FollowingCount int `json:"following_count"`
Followers []string `json:"followers"`
FollowersCount int `json:"followers_count"`
Likes []UserLike `json:"likes"`
SubmissionsCount int `json:"submissions_count"`
CommentsCount int `json:"comments_count"`
}

// UserPrivate represent a user with sensitive fields included.
Expand Down
50 changes: 18 additions & 32 deletions internal/file/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,26 +389,21 @@ func (s service) Like(ctx context.Context, sha256 string) error {
// Get the source of the HTTP request from the ctx.
source, _ := ctx.Value(entity.SourceKey).(string)

if !isStringInSlice(sha256, user.Likes) {
user.Likes = append(user.Likes, sha256)
user.LikesCount += 1
user, err = s.userSvc.Update(ctx, user.ID(), user)
if err != nil {
return err
}

// add new `like` activity.
if _, err = s.actSvc.Create(ctx, activity.CreateActivityRequest{
Kind: "like",
Username: user.Username,
Target: sha256,
Source: source,
}); err != nil {
return err
}
// Add new `like` activity even if the file is already liked.
if _, err = s.actSvc.Create(ctx, activity.CreateActivityRequest{
Kind: "like",
Username: user.Username,
Target: sha256,
Source: source,
}); err != nil {
return err
}

return nil
newLike := entity.UserLike{
SHA256: sha256,
Timestamp: time.Now().Unix(),
}
return s.userSvc.Like(ctx, user.ID(), newLike)
}

func (s service) Unlike(ctx context.Context, sha256 string) error {
Expand All @@ -419,22 +414,13 @@ func (s service) Unlike(ctx context.Context, sha256 string) error {
return err
}

if isStringInSlice(sha256, user.Likes) {
user.Likes = removeStringFromSlice(user.Likes, sha256)
user.LikesCount -= 1
user, err = s.userSvc.Update(ctx, user.ID(), user)
if err != nil {
return err
}

// delete corresponding activity.
if err = s.actSvc.DeleteWith(ctx, "like", user.ID(),
sha256); err != nil {
return err
}
// delete corresponding activity.
if err = s.actSvc.DeleteWith(ctx, "like", user.ID(),
sha256); err != nil {
return err
}

return nil
return s.userSvc.Unlike(ctx, user.ID(), sha256)
}

func (s service) Rescan(ctx context.Context, sha256 string, input FileScanRequest) error {
Expand Down
28 changes: 28 additions & 0 deletions internal/user/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type Repository interface {
[]interface{}, error)
Activities(ctx context.Context, id string, offset, limit int) ([]interface{}, error)
CountActivities(ctx context.Context) (int, error)
Like(ctx context.Context, id string, userLike entity.UserLike) error
Unlike(ctx context.Context, id, sha256 string) error
}

// repository persists users in database.
Expand Down Expand Up @@ -408,3 +410,29 @@ func (r repository) CountActivities(ctx context.Context) (int, error) {

return count, nil
}

func (r repository) Like(ctx context.Context, id string, userLike entity.UserLike) error {

var results interface{}

params := make(map[string]interface{}, 1)
params["sha256"] = userLike.SHA256
params["ts"] = userLike.Timestamp
params["user"] = id

query := r.db.N1QLQuery[dbcontext.ActionLike]
return r.db.Query(ctx, query, params, &results)
}

func (r repository) Unlike(ctx context.Context, id, sha256 string) error {

var results interface{}

params := make(map[string]interface{}, 1)
params["sha256"] = sha256
params["user"] = id

query := r.db.N1QLQuery[dbcontext.ActionUnlike]
return r.db.Query(ctx, query, params, &results)

}
12 changes: 11 additions & 1 deletion internal/user/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ type Service interface {
UpdateEmail(ctx context.Context, input UpdateEmailRequest) error
GenerateConfirmationEmail(ctx context.Context, user User) (
ConfirmAccountResponse, error)
Like(ctx context.Context, id string, userLike entity.UserLike) error
Unlike(ctx context.Context, id, sha256 string) error
}

var (
Expand Down Expand Up @@ -334,7 +336,7 @@ func (s service) CountLikes(ctx context.Context, id string) (int, error) {
if err != nil {
return 0, err
}
return user.LikesCount, err
return len(user.Likes), err
}

func (s service) CountFollowing(ctx context.Context, id string) (int, error) {
Expand Down Expand Up @@ -564,3 +566,11 @@ func (s service) GenerateConfirmationEmail(ctx context.Context, user User) (

return resp, nil
}

func (s service) Like(ctx context.Context, id string, userLike entity.UserLike) error {
return s.repo.Like(ctx, id, userLike)
}

func (s service) Unlike(ctx context.Context, id, sha256 string) error {
return s.repo.Unlike(ctx, id, sha256)
}

0 comments on commit 5a39f67

Please sign in to comment.