summaryrefslogtreecommitdiff
path: root/data.c
diff options
context:
space:
mode:
authorGravatar byte2026-01-24 21:33:30 +0100
committerGravatar byte2026-01-24 21:33:30 +0100
commitbfd071c63826f4d13d48614cedebfb2f8ea20cf6 (patch)
tree8cc9b766b88fa66d051e55d65d6694570553a17b /data.c
parentAdded a Follow/Unfollow button next to a new follow notification. (diff)
parentMerge pull request 'add susie-q (qr) to artwork' (#528) from pmjv/snac2:maste... (diff)
downloadsnac2-bfd071c63826f4d13d48614cedebfb2f8ea20cf6.tar.gz
snac2-bfd071c63826f4d13d48614cedebfb2f8ea20cf6.tar.xz
snac2-bfd071c63826f4d13d48614cedebfb2f8ea20cf6.zip
Merge pull request 'master' (#7) from grunfink/snac2:master into main
Reviewed-on: https://codeberg.org/byte/snac2/pulls/7
Diffstat (limited to 'data.c')
-rw-r--r--data.c162
1 files changed, 147 insertions, 15 deletions
diff --git a/data.c b/data.c
index d291ba7..f32dc81 100644
--- a/data.c
+++ b/data.c
@@ -1,5 +1,5 @@
1/* snac - A simple, minimalistic ActivityPub instance */ 1/* snac - A simple, minimalistic ActivityPub instance */
2/* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ 2/* copyright (c) 2022 - 2026 grunfink et al. / MIT license */
3 3
4#include "xs.h" 4#include "xs.h"
5#include "xs_hex.h" 5#include "xs_hex.h"
@@ -89,8 +89,15 @@ int srv_open(const char *basedir, int auto_upgrade)
89 else { 89 else {
90 if (xs_number_get(xs_dict_get(srv_config, "layout")) < disk_layout) 90 if (xs_number_get(xs_dict_get(srv_config, "layout")) < disk_layout)
91 error = xs_fmt("ERROR: disk layout changed - execute 'snac upgrade' first"); 91 error = xs_fmt("ERROR: disk layout changed - execute 'snac upgrade' first");
92 else 92 else {
93 ret = 1; 93 if (!check_strip_tool()) {
94 const char *mp = xs_dict_get(srv_config, "mogrify_path");
95 if (mp == NULL) mp = "mogrify";
96 error = xs_fmt("ERROR: strip_exif enabled but '%s' not found or not working (set 'mogrify_path' in server.json)", mp);
97 }
98 else
99 ret = 1;
100 }
94 } 101 }
95 } 102 }
96 103
@@ -1043,6 +1050,14 @@ xs_list *object_children(const char *id)
1043} 1050}
1044 1051
1045 1052
1053xs_list *object_get_emoji_reacts(const char *id)
1054/* returns the list of an object's emoji reactions */
1055{
1056 xs *fn = _object_index_fn(id, "_e.idx");
1057 return index_list(fn, XS_ALL);
1058}
1059
1060
1046xs_list *object_likes(const char *id) 1061xs_list *object_likes(const char *id)
1047{ 1062{
1048 xs *fn = _object_index_fn(id, "_l.idx"); 1063 xs *fn = _object_index_fn(id, "_l.idx");
@@ -1086,12 +1101,26 @@ int object_admire(const char *id, const char *actor, int like)
1086 1101
1087 1102
1088int object_unadmire(const char *id, const char *actor, int like) 1103int object_unadmire(const char *id, const char *actor, int like)
1089/* actor no longer likes or announces this object */ 1104/* actor retrives their likes, announces or emojis this object */
1090{ 1105{
1106 switch (like) {
1107 case 0:
1108 like = 'a';
1109 break;
1110 case 1:
1111 like = 'l';
1112 break;
1113 case 2:
1114 like = 'e';
1115 break;
1116 }
1091 int status; 1117 int status;
1092 xs *fn = _object_fn(id); 1118 xs *fn = _object_fn(id);
1093 1119
1094 fn = xs_replace_i(fn, ".json", like ? "_l.idx" : "_a.idx"); 1120 char sfx[7] = "_x.idx";
1121 sfx[1] = like;
1122
1123 fn = xs_replace_i(fn, ".json", sfx);
1095 1124
1096 status = index_del(fn, actor); 1125 status = index_del(fn, actor);
1097 1126
@@ -1099,7 +1128,46 @@ int object_unadmire(const char *id, const char *actor, int like)
1099 index_gc(fn); 1128 index_gc(fn);
1100 1129
1101 srv_debug(0, 1130 srv_debug(0,
1102 xs_fmt("object_unadmire (%s) %s %s %d", like ? "Like" : "Announce", actor, fn, status)); 1131 xs_fmt("object_unadmire (%s) %s %s %d", like >= 'e' ?
1132 (like == 'l' ? "Like" : "EmojiReact") : "Announce" , actor, fn, status));
1133
1134 return status;
1135}
1136
1137int object_emoji_react(const char *mid, const char *eid)
1138/* actor reacts w/ an emoji */
1139{
1140 int status = HTTP_STATUS_OK;
1141 xs *fn = _object_fn(mid);
1142
1143 fn = xs_replace_i(fn, ".json", "_e.idx");
1144
1145 if (!index_in(fn, eid)) {
1146 status = index_add(fn, eid);
1147
1148 srv_debug(1, xs_fmt("object_emoji_react (%s) added %s to %s", "EmojiReact", eid, fn));
1149 }
1150
1151 return status;
1152}
1153
1154
1155int object_rm_emoji_react(const char *mid, const char *eid)
1156/* actor retrives their emoji reaction */
1157{
1158 int status;
1159 xs *fn = _object_fn(mid);
1160
1161 fn = xs_replace_i(fn, ".json", "_e.idx");
1162
1163 status = index_del(fn, eid);
1164 object_del(eid);
1165
1166 if (valid_status(status))
1167 index_gc(fn);
1168
1169 srv_debug(0,
1170 xs_fmt("object_unadmire (EmojiReact) %s %s %d", eid, fn, status));
1103 1171
1104 return status; 1172 return status;
1105} 1173}
@@ -1358,6 +1426,20 @@ int pending_count(snac *user)
1358} 1426}
1359 1427
1360 1428
1429int is_msg_mine(snac *user, const char *id)
1430/* returns true if a post id is by the given user */
1431{
1432 int ret = 0;
1433
1434 if (xs_is_string(id)) {
1435 xs *s1 = xs_fmt("%s/", user->actor);
1436 ret = xs_startswith(id, s1);
1437 }
1438
1439 return ret;
1440}
1441
1442
1361/** timeline **/ 1443/** timeline **/
1362 1444
1363double timeline_mtime(snac *snac) 1445double timeline_mtime(snac *snac)
@@ -1453,7 +1535,7 @@ void timeline_update_indexes(snac *snac, const char *id)
1453{ 1535{
1454 object_user_cache_add(snac, id, "private"); 1536 object_user_cache_add(snac, id, "private");
1455 1537
1456 if (xs_startswith(id, snac->actor)) { 1538 if (is_msg_mine(snac, id)) {
1457 xs *msg = NULL; 1539 xs *msg = NULL;
1458 1540
1459 if (valid_status(object_get(id, &msg))) { 1541 if (valid_status(object_get(id, &msg))) {
@@ -1492,19 +1574,48 @@ int timeline_add(snac *snac, const char *id, const xs_dict *o_msg)
1492} 1574}
1493 1575
1494 1576
1495int timeline_admire(snac *snac, const char *id, const char *admirer, int like) 1577int timeline_emoji_react(const char *act, const char *id, const xs_dict *msg_o)
1496/* updates a timeline entry with a new admiration */ 1578/* adds an emoji reaction to a message */
1497{ 1579{
1580 xs *msg = xs_dup(msg_o);
1581 msg = xs_dict_append(msg, "attributedTo", act);
1582 msg = xs_dict_set(msg, "type", "EmojiReact");
1583 const char *emote_id = xs_dict_get(msg, "id");
1584
1585 int ret = object_add(emote_id, msg);
1586 if (ret == HTTP_STATUS_OK || ret == HTTP_STATUS_CREATED)
1587 ret = object_emoji_react(id, emote_id);
1588
1589 return ret;
1590}
1591
1592
1593int timeline_admire(snac *snac, const char *id,
1594 const char *admirer, int like, const xs_dict *msg)
1595/* updates a timeline entry with a new admiration or emoji reaction */
1596{
1597 int ret;
1598 const char *content = xs_dict_get_path(msg, "content");
1599 const char *type = xs_dict_get_path(msg, "type");
1600
1498 /* if we are admiring this, add to both timelines */ 1601 /* if we are admiring this, add to both timelines */
1499 if (!like && strcmp(admirer, snac->actor) == 0) { 1602 if (!like && strcmp(admirer, snac->actor) == 0) {
1500 object_user_cache_add(snac, id, "public"); 1603 object_user_cache_add(snac, id, "public");
1501 object_user_cache_add(snac, id, "private"); 1604 object_user_cache_add(snac, id, "private");
1502 } 1605 }
1503 1606
1504 int ret = object_admire(id, admirer, like); 1607 /* use utf <3 as a like, as it is ugly */
1608 if (type && xs_match(type, "Like|EmojiReact|Emoji") &&
1609 content && strcmp(content, "❤") != 0) {
1610 ret = timeline_emoji_react(snac->actor, id, msg);
1611 snac_debug(snac, 1, xs_fmt("timeline_emoji_react %s", id));
1612 }
1505 1613
1506 snac_debug(snac, 1, xs_fmt("timeline_admire (%s) %s %s", 1614 else {
1507 like ? "Like" : "Announce", id, admirer)); 1615 ret = object_admire(id, admirer, like);
1616 snac_debug(snac, 1, xs_fmt("timeline_admire (%s) %s %s",
1617 like ? "Like" : "Announce", id, admirer));
1618 }
1508 1619
1509 return ret; 1620 return ret;
1510} 1621}
@@ -1853,6 +1964,25 @@ xs_list *muted_list(snac *user)
1853 return l; 1964 return l;
1854} 1965}
1855 1966
1967/** emojis react **/
1968
1969xs_str *emoji_reacted(snac *user, const char *id)
1970/* returns the emoji an user reacted to a message */
1971{
1972 xs *emojis = object_get_emoji_reacts(id);
1973 int c = 0;
1974 const char *v;
1975
1976 while (xs_list_next(emojis, &v, &c)) {
1977 xs *msg = NULL;
1978 if (object_get_by_md5(v, &msg)) {
1979 const xs_val *act = xs_dict_get(msg, "actor");
1980 if (act && strcmp(act, user->actor) == 0)
1981 return xs_dup(xs_dict_get(msg, "content"));
1982 }
1983 }
1984 return NULL;
1985}
1856 1986
1857/** bookmarking **/ 1987/** bookmarking **/
1858 1988
@@ -1913,7 +2043,7 @@ int pin(snac *user, const char *id)
1913{ 2043{
1914 int ret = -2; 2044 int ret = -2;
1915 2045
1916 if (xs_startswith(id, user->actor)) { 2046 if (is_msg_mine(user, id)) {
1917 if (is_pinned(user, id)) 2047 if (is_pinned(user, id))
1918 ret = -3; 2048 ret = -3;
1919 else 2049 else
@@ -2587,6 +2717,8 @@ void static_put(snac *snac, const char *id, const char *data, int size)
2587 if (fn && (f = fopen(fn, "wb")) != NULL) { 2717 if (fn && (f = fopen(fn, "wb")) != NULL) {
2588 fwrite(data, size, 1, f); 2718 fwrite(data, size, 1, f);
2589 fclose(f); 2719 fclose(f);
2720
2721 strip_media(fn);
2590 } 2722 }
2591} 2723}
2592 2724
@@ -3513,7 +3645,7 @@ void enqueue_output(snac *snac, const xs_dict *msg,
3513 const xs_str *inbox, int retries, int p_status) 3645 const xs_str *inbox, int retries, int p_status)
3514/* enqueues an output message to an inbox */ 3646/* enqueues an output message to an inbox */
3515{ 3647{
3516 if (xs_startswith(inbox, snac->actor)) { 3648 if (is_msg_mine(snac, inbox)) {
3517 snac_debug(snac, 1, xs_str_new("refusing enqueue to myself")); 3649 snac_debug(snac, 1, xs_str_new("refusing enqueue to myself"));
3518 return; 3650 return;
3519 } 3651 }
@@ -4041,7 +4173,7 @@ void delete_purged_posts(snac *user, int days)
4041 if (xs_is_dict(msg)) { 4173 if (xs_is_dict(msg)) {
4042 const char *id = xs_dict_get(msg, "id"); 4174 const char *id = xs_dict_get(msg, "id");
4043 4175
4044 if (xs_is_string(id) && xs_startswith(id, user->actor)) { 4176 if (xs_is_string(id) && is_msg_mine(user, id)) {
4045 xs *d_msg = msg_delete(user, id); 4177 xs *d_msg = msg_delete(user, id);
4046 4178
4047 enqueue_message(user, d_msg); 4179 enqueue_message(user, d_msg);