Always update snippet tags on every Discord edit
This commit is contained in:
parent
5344e9d4bc
commit
4d63d02533
|
@ -7,7 +7,7 @@ fi
|
||||||
. cinera.conf
|
. cinera.conf
|
||||||
|
|
||||||
if [ ! -d $CINERA_HMML_PATH ]; then
|
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
|
fi
|
||||||
|
|
||||||
if [ ! -d $CINERA_HMML_PATH ]; then
|
if [ ! -d $CINERA_HMML_PATH ]; then
|
||||||
|
|
|
@ -7,7 +7,7 @@ fi
|
||||||
. cinera.conf
|
. cinera.conf
|
||||||
|
|
||||||
if [ ! -d $CINERA_REPO_PATH ]; then
|
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
|
fi
|
||||||
|
|
||||||
if [ ! -d $CINERA_REPO_PATH ]; then
|
if [ ! -d $CINERA_REPO_PATH ]; then
|
||||||
|
|
|
@ -176,7 +176,7 @@ if [ $checkpoint -lt 82 ]; then
|
||||||
do_as hmn <<'SCRIPT'
|
do_as hmn <<'SCRIPT'
|
||||||
set -euxo pipefail
|
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
|
set +x
|
||||||
|
|
||||||
echo "Copy the following key:"
|
echo "Copy the following key:"
|
||||||
|
@ -192,7 +192,7 @@ if [ $checkpoint -lt 82 ]; then
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
|
||||||
do_as annotations <<'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
|
set +x
|
||||||
|
|
||||||
echo "Copy the following key:"
|
echo "Copy the following key:"
|
||||||
|
@ -206,7 +206,7 @@ SCRIPT
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
set +x
|
||||||
|
|
||||||
echo "Copy the following key:"
|
echo "Copy the following key:"
|
||||||
|
@ -230,7 +230,7 @@ if [ $checkpoint -lt 90 ]; then
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
|
|
||||||
cd ~
|
cd ~
|
||||||
git clone git@gitssh.handmade.network:hmn/hmn.git
|
git clone git@git.handmade.network:hmn/hmn.git
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
|
||||||
savecheckpoint 90
|
savecheckpoint 90
|
||||||
|
|
|
@ -200,7 +200,7 @@ func handleHistoryMessage(ctx context.Context, dbConn *pgxpool.Pool, msg *Messag
|
||||||
}
|
}
|
||||||
if createSnippets {
|
if createSnippets {
|
||||||
if doSnippet, err := AllowedToCreateMessageSnippet(ctx, tx, newMsg.UserID); doSnippet && err == nil {
|
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 {
|
if err != nil {
|
||||||
return err
|
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")
|
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 {
|
func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message) error {
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case MessageTypeDefault, MessageTypeReply, MessageTypeApplicationCommand:
|
case MessageTypeDefault, MessageTypeReply, MessageTypeApplicationCommand:
|
||||||
|
@ -59,67 +58,10 @@ func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if doSnippet, err := AllowedToCreateMessageSnippet(ctx, tx, newMsg.UserID); doSnippet && err == nil {
|
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 {
|
if err != nil {
|
||||||
return oops.New(err, "failed to create snippet in gateway")
|
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 {
|
} else if err != nil {
|
||||||
return oops.New(err, "failed to check snippet permissions in gateway")
|
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.
|
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
|
// Check for existing snippet, maybe return it
|
||||||
type existingSnippetResult struct {
|
type existingSnippetResult struct {
|
||||||
Message models.DiscordMessage `db:"msg"`
|
Message models.DiscordMessage `db:"msg"`
|
||||||
|
@ -644,13 +593,14 @@ func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*m
|
||||||
contentMarkdown := existing.MessageContent.LastContent
|
contentMarkdown := existing.MessageContent.LastContent
|
||||||
contentHTML := parsing.ParseMarkdown(contentMarkdown, parsing.DiscordMarkdown)
|
contentHTML := parsing.ParseMarkdown(contentMarkdown, parsing.DiscordMarkdown)
|
||||||
|
|
||||||
_, err := tx.Exec(ctx,
|
iSnippet, err := db.QueryOne(ctx, tx, models.Snippet{},
|
||||||
`
|
`
|
||||||
UPDATE handmade_snippet
|
UPDATE handmade_snippet
|
||||||
SET
|
SET
|
||||||
description = $1,
|
description = $1,
|
||||||
_description_html = $2
|
_description_html = $2
|
||||||
WHERE id = $3
|
WHERE id = $3
|
||||||
|
RETURNING $columns
|
||||||
`,
|
`,
|
||||||
contentMarkdown,
|
contentMarkdown,
|
||||||
contentHTML,
|
contentHTML,
|
||||||
|
@ -659,9 +609,11 @@ func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*m
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.ExtractLogger(ctx).Warn().Err(err).Msg("failed to update content of snippet on message edit")
|
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 {
|
if existing.Message.SnippetCreated {
|
||||||
// A snippet once existed but no longer does
|
// A snippet once existed but no longer does
|
||||||
|
@ -716,6 +668,94 @@ func CreateMessageSnippet(ctx context.Context, tx db.ConnOrTx, msgID string) (*m
|
||||||
return isnippet.(*models.Snippet), nil
|
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
|
// 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?
|
// do we actually want to reuse those, or should we keep them separate?
|
||||||
var RESnippetableUrl = regexp.MustCompile(`^https?://(youtu\.be|(www\.)?youtube\.com/watch)`)
|
var RESnippetableUrl = regexp.MustCompile(`^https?://(youtu\.be|(www\.)?youtube\.com/watch)`)
|
||||||
|
|
|
@ -173,7 +173,7 @@ func DiscordShowcaseBacklog(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
for _, imsgId := range msgIds {
|
for _, imsgId := range msgIds {
|
||||||
msgId := imsgId.(*messageIdQuery)
|
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 {
|
if err != nil {
|
||||||
c.Logger.Warn().Err(err).Msg("failed to create snippet from showcase backlog")
|
c.Logger.Warn().Err(err).Msg("failed to create snippet from showcase backlog")
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in New Issue