This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / db / comments.go
5.7 kB 268 lines
1package db 2 3import ( 4 "database/sql" 5 "encoding/json" 6 "fmt" 7 "sort" 8 "strings" 9 "time" 10 11 "github.com/bluesky-social/indigo/api/atproto" 12 "github.com/bluesky-social/indigo/atproto/syntax" 13 "tangled.org/core/api/tangled" 14 "tangled.org/core/appview/models" 15 "tangled.org/core/orm" 16) 17 18func PutComment(tx *sql.Tx, c *models.Comment, references []syntax.ATURI) error { 19 if c.Collection == "" { 20 c.Collection = tangled.FeedCommentNSID 21 } 22 23 var bodyBlobs, replyToUri, replyToCid *string 24 if len(c.Body.Blobs) > 0 { 25 encoded, err := json.Marshal(c.Body.Blobs) 26 if err != nil { 27 return fmt.Errorf("encoding blobs to json: %w", err) 28 } 29 encodedStr := string(encoded) 30 bodyBlobs = &encodedStr 31 } 32 if c.ReplyTo != nil { 33 replyToUri = &c.ReplyTo.Uri 34 replyToCid = &c.ReplyTo.Cid 35 } 36 result, err := tx.Exec( 37 // users can change the 'created' date. 38 // skip update entirely if cid is unchanged. 39 `insert into comments ( 40 did, 41 collection, 42 rkey, 43 cid, 44 subject_uri, 45 subject_cid, 46 body_text, 47 body_original, 48 body_blobs, 49 created, 50 reply_to_uri, 51 reply_to_cid, 52 pull_round_idx 53 ) 54 values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 55 on conflict(did, collection, rkey) 56 do update set 57 cid = excluded.cid, 58 subject_uri = excluded.subject_uri, 59 subject_cid = excluded.subject_cid, 60 body_text = excluded.body_text, 61 body_original = excluded.body_original, 62 body_blobs = excluded.body_blobs, 63 created = excluded.created, 64 reply_to_uri = excluded.reply_to_uri, 65 reply_to_cid = excluded.reply_to_cid, 66 pull_round_idx = excluded.pull_round_idx, 67 edited = ? 68 where comments.cid is not excluded.cid`, 69 c.Did, 70 c.Collection, 71 c.Rkey, 72 c.Cid, 73 c.Subject.Uri, 74 c.Subject.Cid, 75 c.Body.Text, 76 c.Body.Original, 77 bodyBlobs, 78 c.Created.Format(time.RFC3339), 79 replyToUri, 80 replyToCid, 81 c.PullRoundIdx, 82 time.Now().Format(time.RFC3339), 83 ) 84 if err != nil { 85 return err 86 } 87 88 c.Id, err = result.LastInsertId() 89 if err != nil { 90 return err 91 } 92 93 affected, err := result.RowsAffected() 94 if err != nil { 95 return err 96 } 97 98 if affected > 0 { 99 // update references when comment is updated 100 if err := putReferences(tx, c.AtUri(), references); err != nil { 101 return fmt.Errorf("put reference_links: %w", err) 102 } 103 } 104 105 return nil 106} 107 108// PurgeComments actually purges a comment row from db instead of marking it as "deleted" 109func PurgeComments(e Execer, filters ...orm.Filter) error { 110 var conditions []string 111 var args []any 112 for _, filter := range filters { 113 conditions = append(conditions, filter.Condition()) 114 args = append(args, filter.Arg()...) 115 } 116 117 whereClause := "" 118 if conditions != nil { 119 whereClause = " where " + strings.Join(conditions, " and ") 120 } 121 122 _, err := e.Exec(fmt.Sprintf(`delete from comments %s`, whereClause), args...) 123 return err 124} 125 126func DeleteComments(e Execer, filters ...orm.Filter) error { 127 var conditions []string 128 var args []any 129 for _, filter := range filters { 130 conditions = append(conditions, filter.Condition()) 131 args = append(args, filter.Arg()...) 132 } 133 134 whereClause := "" 135 if conditions != nil { 136 whereClause = " where " + strings.Join(conditions, " and ") 137 } 138 139 query := fmt.Sprintf( 140 `update comments 141 set body_text = "", 142 body_original = null, 143 body_blobs = null, 144 deleted = strftime('%%Y-%%m-%%dT%%H:%%M:%%SZ', 'now') 145 %s`, 146 whereClause, 147 ) 148 149 _, err := e.Exec(query, args...) 150 return err 151} 152 153func GetComments(e Execer, filters ...orm.Filter) ([]models.Comment, error) { 154 var comments []models.Comment 155 156 var conditions []string 157 var args []any 158 for _, filter := range filters { 159 conditions = append(conditions, filter.Condition()) 160 args = append(args, filter.Arg()...) 161 } 162 163 whereClause := "" 164 if conditions != nil { 165 whereClause = " where " + strings.Join(conditions, " and ") 166 } 167 168 query := fmt.Sprintf(` 169 select 170 id, 171 did, 172 collection, 173 rkey, 174 cid, 175 subject_uri, 176 subject_cid, 177 body_text, 178 body_original, 179 body_blobs, 180 created, 181 reply_to_uri, 182 reply_to_cid, 183 pull_round_idx, 184 edited, 185 deleted 186 from 187 comments 188 %s 189 `, whereClause) 190 191 rows, err := e.Query(query, args...) 192 if err != nil { 193 return nil, err 194 } 195 defer rows.Close() 196 197 for rows.Next() { 198 var comment models.Comment 199 var created string 200 var cid, bodyBlobs, replyToUri, replyToCid, edited, deleted sql.Null[string] 201 err := rows.Scan( 202 &comment.Id, 203 &comment.Did, 204 &comment.Collection, 205 &comment.Rkey, 206 &cid, 207 &comment.Subject.Uri, 208 &comment.Subject.Cid, 209 &comment.Body.Text, 210 &comment.Body.Original, 211 &bodyBlobs, 212 &created, 213 &replyToUri, 214 &replyToCid, 215 &comment.PullRoundIdx, 216 &edited, 217 &deleted, 218 ) 219 if err != nil { 220 return nil, err 221 } 222 223 if cid.Valid && cid.V != "" { 224 comment.Cid = syntax.CID(cid.V) 225 } 226 227 if bodyBlobs.Valid && bodyBlobs.V != "" { 228 if err := json.Unmarshal([]byte(bodyBlobs.V), &comment.Body.Blobs); err != nil { 229 return nil, fmt.Errorf("decoding blobs: %w", err) 230 } 231 } 232 233 if t, err := time.Parse(time.RFC3339, created); err == nil { 234 comment.Created = t 235 } 236 237 if replyToUri.Valid && replyToCid.Valid { 238 comment.ReplyTo = &atproto.RepoStrongRef{ 239 Uri: replyToUri.V, 240 Cid: replyToCid.V, 241 } 242 } 243 244 if edited.Valid { 245 if t, err := time.Parse(time.RFC3339, edited.V); err == nil { 246 comment.Edited = &t 247 } 248 } 249 250 if deleted.Valid { 251 if t, err := time.Parse(time.RFC3339, deleted.V); err == nil { 252 comment.Deleted = &t 253 } 254 } 255 256 comments = append(comments, comment) 257 } 258 259 if err := rows.Err(); err != nil { 260 return nil, err 261 } 262 263 sort.Slice(comments, func(i, j int) bool { 264 return comments[i].Created.Before(comments[j].Created) 265 }) 266 267 return comments, nil 268}