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