Monorepo for Tangled tangled.org
3

Configure Feed

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

1package db 2 3import ( 4 "database/sql" 5 "fmt" 6 "strings" 7 "time" 8 9 "tangled.org/core/appview/models" 10 "tangled.org/core/orm" 11) 12 13// GetWebhooks returns all webhooks for a repository 14func GetWebhooks(e Execer, filters ...orm.Filter) ([]models.Webhook, error) { 15 var conditions []string 16 var args []any 17 for _, filter := range filters { 18 conditions = append(conditions, filter.Condition()) 19 args = append(args, filter.Arg()...) 20 } 21 22 whereClause := "" 23 if conditions != nil { 24 whereClause = " where " + strings.Join(conditions, " and ") 25 } 26 27 query := fmt.Sprintf(` 28 select 29 id, 30 repo_did, 31 url, 32 secret, 33 active, 34 events, 35 created_at, 36 updated_at 37 from webhooks 38 %s 39 order by created_at desc 40 `, whereClause) 41 42 rows, err := e.Query(query, args...) 43 if err != nil { 44 return nil, fmt.Errorf("failed to query webhooks: %w", err) 45 } 46 defer rows.Close() 47 48 var webhooks []models.Webhook 49 for rows.Next() { 50 var wh models.Webhook 51 var createdAt, updatedAt, eventsStr string 52 var secret sql.NullString 53 var active int 54 55 err := rows.Scan( 56 &wh.Id, 57 &wh.RepoDid, 58 &wh.Url, 59 &secret, 60 &active, 61 &eventsStr, 62 &createdAt, 63 &updatedAt, 64 ) 65 if err != nil { 66 return nil, fmt.Errorf("failed to scan webhook: %w", err) 67 } 68 69 if secret.Valid { 70 wh.Secret = secret.String 71 } 72 wh.Active = active == 1 73 if eventsStr != "" { 74 wh.Events = strings.Split(eventsStr, ",") 75 } 76 77 if t, err := time.Parse(time.RFC3339, createdAt); err == nil { 78 wh.CreatedAt = t 79 } 80 if t, err := time.Parse(time.RFC3339, updatedAt); err == nil { 81 wh.UpdatedAt = t 82 } 83 84 webhooks = append(webhooks, wh) 85 } 86 87 if err = rows.Err(); err != nil { 88 return nil, fmt.Errorf("failed to iterate webhooks: %w", err) 89 } 90 91 return webhooks, nil 92} 93 94// GetWebhook returns a single webhook by ID 95func GetWebhook(e Execer, id int64) (*models.Webhook, error) { 96 webhooks, err := GetWebhooks(e, orm.FilterEq("id", id)) 97 if err != nil { 98 return nil, err 99 } 100 101 if len(webhooks) == 0 { 102 return nil, sql.ErrNoRows 103 } 104 105 if len(webhooks) != 1 { 106 return nil, fmt.Errorf("expected 1 webhook, got %d", len(webhooks)) 107 } 108 109 return &webhooks[0], nil 110} 111 112// AddWebhook creates a new webhook 113func AddWebhook(e Execer, webhook *models.Webhook) error { 114 eventsStr := strings.Join(webhook.Events, ",") 115 active := 0 116 if webhook.Active { 117 active = 1 118 } 119 120 result, err := e.Exec(` 121 insert into webhooks (repo_did, url, secret, active, events) 122 values (?, ?, ?, ?, ?) 123 `, string(webhook.RepoDid), webhook.Url, webhook.Secret, active, eventsStr) 124 125 if err != nil { 126 return fmt.Errorf("failed to insert webhook: %w", err) 127 } 128 129 id, err := result.LastInsertId() 130 if err != nil { 131 return fmt.Errorf("failed to get webhook id: %w", err) 132 } 133 134 webhook.Id = id 135 return nil 136} 137 138// UpdateWebhook updates an existing webhook 139func UpdateWebhook(e Execer, webhook *models.Webhook) error { 140 eventsStr := strings.Join(webhook.Events, ",") 141 active := 0 142 if webhook.Active { 143 active = 1 144 } 145 146 _, err := e.Exec(` 147 update webhooks 148 set url = ?, secret = ?, active = ?, events = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') 149 where id = ? 150 `, webhook.Url, webhook.Secret, active, eventsStr, webhook.Id) 151 152 if err != nil { 153 return fmt.Errorf("failed to update webhook: %w", err) 154 } 155 156 return nil 157} 158 159// DeleteWebhook deletes a webhook 160func DeleteWebhook(e Execer, id int64) error { 161 _, err := e.Exec(`delete from webhooks where id = ?`, id) 162 if err != nil { 163 return fmt.Errorf("failed to delete webhook: %w", err) 164 } 165 return nil 166} 167 168// AddWebhookDelivery records a webhook delivery attempt 169func AddWebhookDelivery(e Execer, delivery *models.WebhookDelivery) error { 170 success := 0 171 if delivery.Success { 172 success = 1 173 } 174 175 result, err := e.Exec(` 176 insert into webhook_deliveries ( 177 webhook_id, 178 event, 179 delivery_id, 180 url, 181 request_body, 182 response_code, 183 response_body, 184 success 185 ) values (?, ?, ?, ?, ?, ?, ?, ?) 186 `, 187 delivery.WebhookId, 188 delivery.Event, 189 delivery.DeliveryId, 190 delivery.Url, 191 delivery.RequestBody, 192 delivery.ResponseCode, 193 delivery.ResponseBody, 194 success, 195 ) 196 197 if err != nil { 198 return fmt.Errorf("failed to insert webhook delivery: %w", err) 199 } 200 201 id, err := result.LastInsertId() 202 if err != nil { 203 return fmt.Errorf("failed to get delivery id: %w", err) 204 } 205 206 delivery.Id = id 207 return nil 208} 209 210// GetWebhookDeliveries returns recent deliveries for a webhook 211func GetWebhookDeliveries(e Execer, webhookId int64, limit int) ([]models.WebhookDelivery, error) { 212 if limit <= 0 { 213 limit = 20 214 } 215 216 query := ` 217 select 218 id, 219 webhook_id, 220 event, 221 delivery_id, 222 url, 223 request_body, 224 response_code, 225 response_body, 226 success, 227 created_at 228 from webhook_deliveries 229 where webhook_id = ? 230 order by created_at desc 231 limit ? 232 ` 233 234 rows, err := e.Query(query, webhookId, limit) 235 if err != nil { 236 return nil, fmt.Errorf("failed to query webhook deliveries: %w", err) 237 } 238 defer rows.Close() 239 240 var deliveries []models.WebhookDelivery 241 for rows.Next() { 242 var d models.WebhookDelivery 243 var createdAt string 244 var success int 245 var responseCode sql.NullInt64 246 var responseBody sql.NullString 247 248 err := rows.Scan( 249 &d.Id, 250 &d.WebhookId, 251 &d.Event, 252 &d.DeliveryId, 253 &d.Url, 254 &d.RequestBody, 255 &responseCode, 256 &responseBody, 257 &success, 258 &createdAt, 259 ) 260 if err != nil { 261 return nil, fmt.Errorf("failed to scan delivery: %w", err) 262 } 263 264 d.Success = success == 1 265 if responseCode.Valid { 266 d.ResponseCode = int(responseCode.Int64) 267 } 268 if responseBody.Valid { 269 d.ResponseBody = responseBody.String 270 } 271 272 if t, err := time.Parse(time.RFC3339, createdAt); err == nil { 273 d.CreatedAt = t 274 } 275 276 deliveries = append(deliveries, d) 277 } 278 279 if err = rows.Err(); err != nil { 280 return nil, fmt.Errorf("failed to iterate deliveries: %w", err) 281 } 282 283 return deliveries, nil 284} 285 286// GetWebhooksForRepo is a convenience function to get all webhooks for a repository 287func GetWebhooksForRepo(e Execer, repoDid string) ([]models.Webhook, error) { 288 return GetWebhooks(e, orm.FilterEq("repo_did", repoDid)) 289} 290 291// GetActiveWebhooksForRepo returns only active webhooks for a repository 292func GetActiveWebhooksForRepo(e Execer, repoDid string) ([]models.Webhook, error) { 293 return GetWebhooks(e, 294 orm.FilterEq("repo_did", repoDid), 295 orm.FilterEq("active", 1), 296 ) 297}