Always update snippet tags on every Discord edit
This commit is contained in:
parent
5344e9d4bc
commit
4d63d02533
|
@ -7,7 +7,7 @@ fi
|
|||
. cinera.conf
|
||||
|
||||
if [ ! -d $CINERA_HMML_PATH ]; then
|
||||
git clone --config core.sshCommand="ssh -i ~/.ssh/gitlab-hmml" git@gitssh.handmade.network:Annotation-Pushers/cinera_handmade.network.git $CINERA_HMML_PATH
|
||||
git clone --config core.sshCommand="ssh -i ~/.ssh/gitlab-hmml" git@git.handmade.network:Annotation-Pushers/cinera_handmade.network.git $CINERA_HMML_PATH
|
||||
fi
|
||||
|
||||
if [ ! -d $CINERA_HMML_PATH ]; then
|
||||
|
|
|
@ -7,7 +7,7 @@ fi
|
|||
. cinera.conf
|
||||
|
||||
if [ ! -d $CINERA_REPO_PATH ]; then
|
||||
git clone --config core.sshCommand="ssh -i ~/.ssh/gitlab-annotation-system" git@gitssh.handmade.network:Annotation-Pushers/Annotation-System.git $CINERA_REPO_PATH
|
||||
git clone --config core.sshCommand="ssh -i ~/.ssh/gitlab-annotation-system" git@git.handmade.network:Annotation-Pushers/Annotation-System.git $CINERA_REPO_PATH
|
||||
fi
|
||||
|
||||
if [ ! -d $CINERA_REPO_PATH ]; then
|
||||
|
|
|
@ -176,7 +176,7 @@ if [ $checkpoint -lt 82 ]; then
|
|||
do_as hmn <<'SCRIPT'
|
||||
set -euxo pipefail
|
||||
|
||||
if ! ssh -T -i ~/.ssh/gitlab-hmn git@gitssh.handmade.network; then
|
||||
if ! ssh -T -i ~/.ssh/gitlab-hmn git@git.handmade.network; then
|
||||
set +x
|
||||
|
||||
echo "Copy the following key:"
|
||||
|
@ -192,7 +192,7 @@ if [ $checkpoint -lt 82 ]; then
|
|||
SCRIPT
|
||||
|
||||
do_as annotations <<'SCRIPT'
|
||||
if ! ssh -T -i ~/.ssh/gitlab-annotation-system git@gitssh.handmade.network; then
|
||||
if ! ssh -T -i ~/.ssh/gitlab-annotation-system git@git.handmade.network; then
|
||||
set +x
|
||||
|
||||
echo "Copy the following key:"
|
||||
|
@ -206,7 +206,7 @@ SCRIPT
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if ! ssh -T -i ~/.ssh/gitlab-hmml git@gitssh.handmade.network; then
|
||||
if ! ssh -T -i ~/.ssh/gitlab-hmml git@git.handmade.network; then
|
||||
set +x
|
||||
|
||||
echo "Copy the following key:"
|
||||
|
@ -230,7 +230,7 @@ if [ $checkpoint -lt 90 ]; then
|
|||
set -euxo pipefail
|
||||
|
||||
cd ~
|
||||
git clone git@gitssh.handmade.network:hmn/hmn.git
|
||||
git clone git@git.handmade.network:hmn/hmn.git
|
||||
SCRIPT
|
||||
|
||||
savecheckpoint 90
|
||||
|
|
|
@ -200,7 +200,7 @@ func handleHistoryMessage(ctx context.Context, dbConn *pgxpool.Pool, msg *Messag
|
|||
}
|
||||
if createSnippets {
|
||||
if doSnippet, err := AllowedToCreateMessageSnippet(ctx, tx, newMsg.UserID); doSnippet && err == nil {
|
||||
_, err := CreateMessageSnippet(ctx, tx, msg.ID)
|
||||
_, err := CreateMessageSnippet(ctx, tx, newMsg.UserID, msg.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ var reDiscordMessageLink = regexp.MustCompile(`https?://.+?(\s|$)`)
|
|||
|
||||
var errNotEnoughInfo = errors.New("Discord didn't send enough info in this event for us to do this")
|
||||
|
||||
// TODO: Turn this ad-hoc isJam parameter into a tag or something
|
||||
func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message) error {
|
||||
switch msg.Type {
|
||||
case MessageTypeDefault, MessageTypeReply, MessageTypeApplicationCommand:
|
||||
|
@ -59,67 +58,10 @@ func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message) er
|
|||
return err
|
||||
}
|
||||
if doSnippet, err := AllowedToCreateMessageSnippet(ctx, tx, newMsg.UserID); doSnippet && err == nil {
|
||||
snippet, err := CreateMessageSnippet(ctx, tx, msg.ID)
|
||||
_, err := CreateMessageSnippet(ctx, tx, newMsg.UserID, msg.ID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to create snippet in gateway")
|
||||
}
|
||||
|
||||
u, err := FetchDiscordUser(ctx, bot.dbConn, newMsg.UserID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to look up HMN user information from Discord user")
|
||||
// we shouldn't see a "not found" here because of the AllowedToBlahBlahBlah check.
|
||||
}
|
||||
|
||||
projects, err := hmndata.FetchProjects(ctx, bot.dbConn, &u.HMNUser, hmndata.ProjectsQuery{
|
||||
OwnerIDs: []int{u.HMNUser.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to look up user projects")
|
||||
}
|
||||
projectIDs := make([]int, len(projects))
|
||||
for i, p := range projects {
|
||||
projectIDs[i] = p.Project.ID
|
||||
}
|
||||
|
||||
// Try to associate tags in the message with project tags in HMN.
|
||||
// Match only tags for projects in which the current user is a collaborator.
|
||||
messageTags := getDiscordTags(msg.Content)
|
||||
type tagsRow struct {
|
||||
Tag models.Tag `db:"tags"`
|
||||
}
|
||||
itUserTags, err := db.Query(ctx, tx, tagsRow{},
|
||||
`
|
||||
SELECT $columns
|
||||
FROM
|
||||
tags
|
||||
JOIN handmade_project AS project ON project.tag = tags.id
|
||||
JOIN handmade_user_projects AS user_project ON user_project.project_id = project.id
|
||||
WHERE
|
||||
project.id = ANY ($1)
|
||||
`,
|
||||
projectIDs,
|
||||
)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to fetch tags for user projects")
|
||||
}
|
||||
iUserTags := itUserTags.ToSlice()
|
||||
|
||||
var tagIDs []int
|
||||
for _, itag := range iUserTags {
|
||||
tag := itag.(*tagsRow).Tag
|
||||
for _, messageTag := range messageTags {
|
||||
if tag.Text == messageTag {
|
||||
tagIDs = append(tagIDs, tag.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, tagID := range tagIDs {
|
||||
_, err = tx.Exec(ctx, `INSERT INTO snippet_tags (snippet_id, tag_id) VALUES ($1, $2)`, snippet.ID, tagID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to add tag to snippet")
|
||||
}
|
||||
}
|
||||
} else if err != nil {
|
||||
return oops.New(err, "failed to check snippet permissions in gateway")
|
||||
}
|
||||
|
@ -612,7 +554,14 @@ any content saved, nothing will happen.
|
|||
|
||||
Does not check user preferences around snippets.
|
||||
*/
|
||||
func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*models.Snippet, error) {
|
||||
func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, userID, msgID string) (snippet *models.Snippet, err error) {
|
||||
defer func() {
|
||||
err := updateSnippetTags(ctx, tx, userID, snippet)
|
||||
if err != nil {
|
||||
logging.ExtractLogger(ctx).Error().Err(err).Msg("failed to update tags for Discord snippet")
|
||||
}
|
||||
}()
|
||||
|
||||
// Check for existing snippet, maybe return it
|
||||
type existingSnippetResult struct {
|
||||
Message models.DiscordMessage `db:"msg"`
|
||||
|
@ -644,13 +593,14 @@ func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*m
|
|||
contentMarkdown := existing.MessageContent.LastContent
|
||||
contentHTML := parsing.ParseMarkdown(contentMarkdown, parsing.DiscordMarkdown)
|
||||
|
||||
_, err := tx.Exec(ctx,
|
||||
iSnippet, err := db.QueryOne(ctx, tx, models.Snippet{},
|
||||
`
|
||||
UPDATE handmade_snippet
|
||||
SET
|
||||
description = $1,
|
||||
_description_html = $2
|
||||
WHERE id = $3
|
||||
RETURNING $columns
|
||||
`,
|
||||
contentMarkdown,
|
||||
contentHTML,
|
||||
|
@ -659,8 +609,10 @@ func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*m
|
|||
if err != nil {
|
||||
logging.ExtractLogger(ctx).Warn().Err(err).Msg("failed to update content of snippet on message edit")
|
||||
}
|
||||
return iSnippet.(*models.Snippet), nil
|
||||
} else {
|
||||
return existing.Snippet, nil
|
||||
}
|
||||
return existing.Snippet, nil
|
||||
}
|
||||
|
||||
if existing.Message.SnippetCreated {
|
||||
|
@ -716,6 +668,94 @@ func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*m
|
|||
return isnippet.(*models.Snippet), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Associates any Discord tags with website tags. Idempotent; will clear
|
||||
out any existing tags and then add new ones.
|
||||
*/
|
||||
func updateSnippetTags(ctx context.Context, dbConn db.ConnOrTx, userID string, snippet *models.Snippet) error {
|
||||
tx, err := dbConn.Begin(ctx)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to start transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
u, err := FetchDiscordUser(ctx, tx, userID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to look up HMN user information from Discord user")
|
||||
// we shouldn't see a "not found" here because of the AllowedToBlahBlahBlah check earlier in the process
|
||||
}
|
||||
|
||||
projects, err := hmndata.FetchProjects(ctx, tx, &u.HMNUser, hmndata.ProjectsQuery{
|
||||
OwnerIDs: []int{u.HMNUser.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to look up user projects")
|
||||
}
|
||||
projectIDs := make([]int, len(projects))
|
||||
for i, p := range projects {
|
||||
projectIDs[i] = p.Project.ID
|
||||
}
|
||||
|
||||
// Delete any existing tags for this snippet
|
||||
_, err = tx.Exec(ctx,
|
||||
`
|
||||
DELETE FROM snippet_tags
|
||||
WHERE snippet_id = $1
|
||||
`,
|
||||
snippet.ID,
|
||||
)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to delete existing snippet tags")
|
||||
}
|
||||
|
||||
// Try to associate tags in the message with project tags in HMN.
|
||||
// Match only tags for projects in which the current user is a collaborator.
|
||||
messageTags := getDiscordTags(snippet.Description)
|
||||
type tagsRow struct {
|
||||
Tag models.Tag `db:"tags"`
|
||||
}
|
||||
itUserTags, err := db.Query(ctx, tx, tagsRow{},
|
||||
`
|
||||
SELECT $columns
|
||||
FROM
|
||||
tags
|
||||
JOIN handmade_project AS project ON project.tag = tags.id
|
||||
JOIN handmade_user_projects AS user_project ON user_project.project_id = project.id
|
||||
WHERE
|
||||
project.id = ANY ($1)
|
||||
`,
|
||||
projectIDs,
|
||||
)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to fetch tags for user projects")
|
||||
}
|
||||
iUserTags := itUserTags.ToSlice()
|
||||
|
||||
var tagIDs []int
|
||||
for _, itag := range iUserTags {
|
||||
tag := itag.(*tagsRow).Tag
|
||||
for _, messageTag := range messageTags {
|
||||
if tag.Text == messageTag {
|
||||
tagIDs = append(tagIDs, tag.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, tagID := range tagIDs {
|
||||
_, err = tx.Exec(ctx, `INSERT INTO snippet_tags (snippet_id, tag_id) VALUES ($1, $2)`, snippet.ID, tagID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to add tag to snippet")
|
||||
}
|
||||
}
|
||||
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to commit transaction")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE(ben): This is maybe redundant with the regexes we use for markdown. But
|
||||
// do we actually want to reuse those, or should we keep them separate?
|
||||
var RESnippetableUrl = regexp.MustCompile(`^https?://(youtu\.be|(www\.)?youtube\.com/watch)`)
|
||||
|
|
|
@ -173,7 +173,7 @@ func DiscordShowcaseBacklog(c *RequestContext) ResponseData {
|
|||
|
||||
for _, imsgId := range msgIds {
|
||||
msgId := imsgId.(*messageIdQuery)
|
||||
_, err := discord.CreateMessageSnippet(c.Context(), c.Conn, msgId.MessageID)
|
||||
_, err := discord.CreateMessageSnippet(c.Context(), c.Conn, duser.UserID, msgId.MessageID)
|
||||
if err != nil {
|
||||
c.Logger.Warn().Err(err).Msg("failed to create snippet from showcase backlog")
|
||||
continue
|
||||
|
|
Reference in New Issue