pull/52/head
sunface 4 years ago
parent af8c4e85bf
commit 0d3ef5505f

@ -19,6 +19,10 @@ func Follow(c *gin.Context) {
return return
} }
if id == user.ID {
c.JSON(http.StatusBadRequest, common.RespError("无法关注自己"))
return
}
err := interaction.Follow(id, user.ID) err := interaction.Follow(id, user.ID)
if err != nil { if err != nil {
c.JSON(err.Status, common.RespError(err.Message)) c.JSON(err.Status, common.RespError(err.Message))

@ -6,6 +6,7 @@ import (
"sort" "sort"
"time" "time"
"github.com/imdotdev/im.dev/server/internal/notification"
"github.com/imdotdev/im.dev/server/pkg/db" "github.com/imdotdev/im.dev/server/pkg/db"
"github.com/imdotdev/im.dev/server/pkg/e" "github.com/imdotdev/im.dev/server/pkg/e"
"github.com/imdotdev/im.dev/server/pkg/models" "github.com/imdotdev/im.dev/server/pkg/models"
@ -63,6 +64,14 @@ func Follow(targetID string, userId string) *e.Error {
tx.Commit() tx.Commit()
if !followed {
if models.GetIDType(targetID) == models.IDTypeUser {
notification.Send(targetID, "", models.NotificationLike, targetID, userId)
} else {
notification.Send("", targetID, models.NotificationLike, targetID, userId)
}
}
return nil return nil
} }
@ -120,6 +129,23 @@ func GetFollowing(userID, targetType string) ([]*models.Following, *e.Error) {
return following, nil return following, nil
} }
func GetFollowerIDs(targetID string) ([]string, error) {
rows, err := db.Conn.Query("SELECT user_id from follows where target_id=?", targetID)
if err != nil {
logger.Warn("get followers error", "error", err)
return nil, err
}
users := make([]string, 0)
for rows.Next() {
var id string
rows.Scan(&id)
users = append(users, id)
}
return users, nil
}
func GetFollowers(targetID, targetType string) ([]*models.User, *e.Error) { func GetFollowers(targetID, targetType string) ([]*models.User, *e.Error) {
rows, err := db.Conn.Query("SELECT user_id from follows where target_id=? and target_type=? ORDER BY created DESC", targetID, targetType) rows, err := db.Conn.Query("SELECT user_id from follows where target_id=? and target_type=? ORDER BY created DESC", targetID, targetType)
if err != nil { if err != nil {

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/imdotdev/im.dev/server/internal/notification"
"github.com/imdotdev/im.dev/server/internal/top" "github.com/imdotdev/im.dev/server/internal/top"
"github.com/imdotdev/im.dev/server/pkg/db" "github.com/imdotdev/im.dev/server/pkg/db"
"github.com/imdotdev/im.dev/server/pkg/e" "github.com/imdotdev/im.dev/server/pkg/e"
@ -71,6 +72,13 @@ func Like(storyID string, userId string) *e.Error {
top.Update(storyID, count) top.Update(storyID, count)
} }
if !liked {
// send notification to story creator and owner
creator, owner := models.GetStoryCreatorAndOrg(storyID)
if creator != "" {
notification.Send(creator, owner, models.NotificationLike, storyID, userId)
}
}
return nil return nil
} }

@ -0,0 +1,29 @@
package notification
import (
"time"
"github.com/imdotdev/im.dev/server/pkg/db"
"github.com/imdotdev/im.dev/server/pkg/e"
"github.com/imdotdev/im.dev/server/pkg/log"
)
var logger = log.RootLogger.New("logger", "notification")
func Send(userID, orgID string, noType int, noID string, operatorID string) {
if userID != "" {
_, err := db.Conn.Exec("INSERT INTO user_notification (user_id,operator_id,notifiable_type,notifiable_id,created) VALUES (?,?,?,?,?)",
userID, operatorID, noType, noID, time.Now())
if err != nil {
logger.Warn("send notification error", "error", err)
}
}
if orgID != "" {
_, err := db.Conn.Exec("INSERT INTO org_notification (user_id,operator_id,notifiable_type,notifiable_id,created) VALUES (?,?,?,?,?)",
orgID, operatorID, noType, noID, time.Now())
if err != nil && !e.IsErrUniqueConstraint(err) {
logger.Warn("send notification error", "error", err)
}
}
}

@ -248,4 +248,31 @@ var sqlTables = map[string]string{
display_count TINYINT, display_count TINYINT,
weight TINYINT DEFAULT 0 weight TINYINT DEFAULT 0
);`, );`,
"user_notification": `CREATE TABLE IF NOT EXISTS user_notification (
user_id VARCHAR(255),
operator_id VARCHAR(255),
notifiable_type TINYINT,
notifiable_id VARCHAR(255),
read BOOL DEFAULT false,
created DATETIME NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS user_notification_userid_notype_noid
ON user_notification (user_id,operator_id,notifiable_type,notifiable_id);
CREATE INDEX IF NOT EXISTS user_notification_created
ON user_notification (created)
`,
"org_notification": `CREATE TABLE IF NOT EXISTS org_notification (
user_id VARCHAR(255),
operator_id VARCHAR(255),
notifiable_type TINYINT,
notifiable_id VARCHAR(255),
read BOOL DEFAULT false,
created DATETIME NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS org_notification_userid_notype_noid
ON org_notification (user_id,operator_id,notifiable_type,notifiable_id);
CREATE INDEX IF NOT EXISTS user_notification_created
ON org_notification (created)
`,
} }

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/imdotdev/im.dev/server/internal/interaction" "github.com/imdotdev/im.dev/server/internal/interaction"
"github.com/imdotdev/im.dev/server/internal/notification"
"github.com/imdotdev/im.dev/server/pkg/db" "github.com/imdotdev/im.dev/server/pkg/db"
"github.com/imdotdev/im.dev/server/pkg/e" "github.com/imdotdev/im.dev/server/pkg/e"
"github.com/imdotdev/im.dev/server/pkg/models" "github.com/imdotdev/im.dev/server/pkg/models"
@ -55,6 +56,19 @@ func AddComment(c *models.Comment) *e.Error {
} }
} }
} }
// send notification to story creator and org
creator, owner := models.GetStoryCreatorAndOrg(c.TargetID)
if creator != "" && creator != c.CreatorID {
if models.GetIDType(c.TargetID) == models.IDTypeComment {
// reply
notification.Send(creator, owner, models.NotificationReply, c.TargetID, c.CreatorID)
} else {
// comment
notification.Send(creator, owner, models.NotificationComment, c.TargetID, c.CreatorID)
}
}
return nil return nil
} }

@ -2,6 +2,7 @@ package story
import ( import (
"database/sql" "database/sql"
"fmt"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -10,6 +11,7 @@ import (
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/imdotdev/im.dev/server/internal/interaction" "github.com/imdotdev/im.dev/server/internal/interaction"
"github.com/imdotdev/im.dev/server/internal/notification"
"github.com/imdotdev/im.dev/server/internal/org" "github.com/imdotdev/im.dev/server/internal/org"
"github.com/imdotdev/im.dev/server/internal/tags" "github.com/imdotdev/im.dev/server/internal/tags"
"github.com/imdotdev/im.dev/server/internal/top" "github.com/imdotdev/im.dev/server/internal/top"
@ -141,6 +143,24 @@ func SubmitStory(c *gin.Context) (map[string]string, *e.Error) {
likes := interaction.GetLikes(post.ID) likes := interaction.GetLikes(post.ID)
top.Update(post.ID, likes) top.Update(post.ID, likes)
// send notification to creator followers and org followers
followers, err1 := interaction.GetFollowerIDs(post.CreatorID)
if err1 == nil {
for _, f := range followers {
notification.Send(f, "", models.NotificationFollow, post.ID, post.CreatorID)
}
}
if post.OwnerID != "" {
followers, err1 = interaction.GetFollowerIDs(post.OwnerID)
if err1 == nil {
fmt.Println(followers)
for _, f := range followers {
notification.Send("", f, models.NotificationFollow, post.ID, post.CreatorID)
}
}
}
return map[string]string{ return map[string]string{
"username": user.Username, "username": user.Username,
"id": post.ID, "id": post.ID,

@ -0,0 +1,10 @@
package models
const (
NotificationComment = 1
NotificationLike = 2
NotificationMention = 3
NotificationPublish = 4
NotificationFollow = 5
NotificationReply = 6
)

@ -97,3 +97,14 @@ func GetStoryCreated(storyID string) time.Time {
return t return t
} }
func GetStoryCreatorAndOrg(storyID string) (string, string) {
var creator, owner string
if GetIDType(storyID) == IDTypeComment {
db.Conn.QueryRow("SELECT creator FROM comments WHERE id=?", storyID).Scan(&creator)
} else {
db.Conn.QueryRow("SELECT creator,owner FROM story WHERE id=?", storyID).Scan(&creator, &owner)
}
return creator, owner
}

Loading…
Cancel
Save