mirror of https://gitlab.com/ngerakines/tavern.git
Added support for recording tags with user activity.
This commit is contained in:
parent
6c7185c508
commit
a4ad0c4213
|
@ -11,4 +11,9 @@ var tagRegex = `(?:^|\B)([##]{1}(\w+))`
|
|||
func FindMentionedActors(input string) []string {
|
||||
mr := regexp.MustCompile(mentionRegex)
|
||||
return mr.FindAllString(input, -1)
|
||||
}
|
||||
}
|
||||
|
||||
func FindMentionedTags(input string) []string {
|
||||
tr := regexp.MustCompile(tagRegex)
|
||||
return tr.FindAllString(input, -1)
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ type UserStorage interface {
|
|||
GetUserByName(ctx context.Context, name string) (*User, error)
|
||||
GetUserBySession(ctx context.Context, session sessions.Session) (*User, error)
|
||||
UpdateUserLastAuth(ctx context.Context, userID uuid.UUID) error
|
||||
RecordUserActivity(ctx context.Context, userID, activityID uuid.UUID) error
|
||||
PaginateUseActivity(ctx context.Context, userID uuid.UUID, limit, offset int) ([]UserFeed, error)
|
||||
RecordUserActivity(ctx context.Context, userID, activityID uuid.UUID, isPublic bool, tags []string) error
|
||||
PaginateUserActivity(ctx context.Context, userID uuid.UUID, limit, offset int) ([]UserFeed, error)
|
||||
PublicUserActivityByTag(ctx context.Context, tag string, limit, offset int) ([]UserFeed, error)
|
||||
}
|
||||
|
||||
type User struct {
|
||||
|
|
|
@ -4,20 +4,30 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
)
|
||||
|
||||
func (s pgStorage) RecordUserActivity(ctx context.Context, userID, activityID uuid.UUID) error {
|
||||
_, err := s.db.ExecContext(ctx, "INSERT INTO user_activities (id, user_id, activity_id, created_at) VALUES ($1, $2, $3, $4)", NewV4(), userID, activityID, s.now())
|
||||
func (s pgStorage) RecordUserActivity(ctx context.Context, userID, activityID uuid.UUID, isPublic bool, tags []string) error {
|
||||
_, err := s.db.ExecContext(ctx, `INSERT INTO user_activities (id, user_id, activity_id, created_at, "public", tags) VALUES ($1, $2, $3, $4, $5, $6)`, NewV4(), userID, activityID, s.now(), isPublic, pq.Array(tags))
|
||||
return errors.WrapInsertQueryFailedError(err)
|
||||
}
|
||||
|
||||
func (s pgStorage) PaginateUseActivity(ctx context.Context, userID uuid.UUID, limit, offset int) ([]UserFeed, error) {
|
||||
func (s pgStorage) PaginateUserActivity(ctx context.Context, userID uuid.UUID, limit, offset int) ([]UserFeed, error) {
|
||||
query := `SELECT id, user_id, activity_id, created_at FROM user_activities WHERE user_id = $3 ORDER BY created_at ASC LIMIT $1 OFFSET $2`
|
||||
return s.queryUserActivity(ctx, query, limit, offset, userID)
|
||||
}
|
||||
|
||||
func (s pgStorage) PublicUserActivityByTag(ctx context.Context, tag string, limit, offset int) ([]UserFeed, error) {
|
||||
query := `SELECT id, user_id, activity_id, created_at FROM user_activities WHERE public = TRUE AND tags @> ARRAY[$3]::varchar[] ORDER BY created_at ASC LIMIT $1 OFFSET $2`
|
||||
return s.queryUserActivity(ctx, query, limit, offset, tag)
|
||||
}
|
||||
|
||||
func (s pgStorage) queryUserActivity(ctx context.Context, query string, args ...interface{}) ([]UserFeed, error) {
|
||||
var results []UserFeed
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, limit, offset, userID)
|
||||
rows, err := s.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, errors.NewSelectQueryFailedError(err)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
|
@ -58,7 +59,7 @@ func (h handler) dashboardNotes(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
uf, err := h.storage.PaginateUseActivity(ctx, user.ID, limit, (page-1)*limit)
|
||||
uf, err := h.storage.PaginateUserActivity(ctx, user.ID, limit, (page-1)*limit)
|
||||
if err != nil {
|
||||
h.hardFail(c, err)
|
||||
return
|
||||
|
@ -166,6 +167,11 @@ func (h handler) createNote(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
mentionedTags := storage.FindMentionedTags(content)
|
||||
|
||||
isPublic := true
|
||||
firstTags := make([]string, 0)
|
||||
|
||||
createNoteID := storage.NewV4()
|
||||
createNote := storage.EmptyPayload()
|
||||
createNote["@context"] = "https://www.w3.org/ns/activitystreams"
|
||||
|
@ -189,7 +195,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
note["type"] = "Note"
|
||||
note["url"] = activityURL
|
||||
|
||||
if len(mentionedActors) > 0 {
|
||||
if len(mentionedActors)+len(mentionedTags) > 0 {
|
||||
tag := make([]map[string]interface{}, 0)
|
||||
for name, actor := range mentionedActors {
|
||||
tag = append(tag, map[string]interface{}{
|
||||
|
@ -198,6 +204,17 @@ func (h handler) createNote(c *gin.Context) {
|
|||
"name": name,
|
||||
})
|
||||
}
|
||||
for _, hashtag := range mentionedTags {
|
||||
clean := strings.TrimPrefix(hashtag, "#")
|
||||
tag = append(tag, map[string]interface{}{
|
||||
"type": "Hashtag",
|
||||
"href": fmt.Sprintf("https://%s/tags/%s", h.domain, clean),
|
||||
"name": hashtag,
|
||||
})
|
||||
if len(firstTags) < 5 {
|
||||
firstTags = append(firstTags, clean)
|
||||
}
|
||||
}
|
||||
note["tag"] = tag
|
||||
}
|
||||
|
||||
|
@ -217,7 +234,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
err = h.storage.RecordUserActivity(ctx, user.ID, objectEventID)
|
||||
err = h.storage.RecordUserActivity(ctx, user.ID, objectEventID, isPublic, firstTags)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, "/dashboard/notes", err)
|
||||
return
|
||||
|
@ -319,7 +336,7 @@ func (h handler) announceNote(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
err = h.storage.RecordUserActivity(ctx, user.ID, objectEventID)
|
||||
err = h.storage.RecordUserActivity(ctx, user.ID, objectEventID, true, []string{})
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, "/dashboard/notes", err)
|
||||
return
|
||||
|
|
|
@ -14,10 +14,10 @@ import (
|
|||
)
|
||||
|
||||
func (h handler) nodeInfo(c *gin.Context) {
|
||||
if !requireAccept(c, "application/json") {
|
||||
h.writeJSONError(c, http.StatusNotAcceptable, fmt.Errorf("client does not indicate that they accept application/json responses"))
|
||||
return
|
||||
}
|
||||
// if !requireAccept(c, "application/json") {
|
||||
// h.writeJSONError(c, http.StatusNotAcceptable, fmt.Errorf("client does not indicate that they accept application/json responses"))
|
||||
// return
|
||||
// }
|
||||
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"links": []interface{}{
|
||||
|
@ -30,10 +30,10 @@ func (h handler) nodeInfo(c *gin.Context) {
|
|||
}
|
||||
|
||||
func (h handler) nodeInfoDetails(c *gin.Context) {
|
||||
if !requireAccept(c, "application/json") {
|
||||
h.writeJSONError(c, http.StatusNotAcceptable, fmt.Errorf("client does not indicate that they accept application/json responses"))
|
||||
return
|
||||
}
|
||||
// if !requireAccept(c, "application/json") {
|
||||
// h.writeJSONError(c, http.StatusNotAcceptable, fmt.Errorf("client does not indicate that they accept application/json responses"))
|
||||
// return
|
||||
// }
|
||||
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"version": "2.0",
|
||||
|
@ -55,10 +55,10 @@ func (h handler) nodeInfoDetails(c *gin.Context) {
|
|||
}
|
||||
|
||||
func (h handler) webFinger(c *gin.Context) {
|
||||
if !requireAccept(c, "application/jrd+json") {
|
||||
h.writeJSONError(c, http.StatusNotAcceptable, fmt.Errorf("client does not indicate that they accept application/jrd+json responses"))
|
||||
return
|
||||
}
|
||||
// if !requireAccept(c, "application/jrd+json") {
|
||||
// h.writeJSONError(c, http.StatusNotAcceptable, fmt.Errorf("client does not indicate that they accept application/jrd+json responses"))
|
||||
// return
|
||||
// }
|
||||
|
||||
username, domain, err := fingerUserDomain(c.Query("resource"), h.domain)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue