From 20573275ec8f7cc7f5744a3280590040a6f14203 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 22 Mar 2025 08:32:59 +0100 Subject: mastoapi: Added support for /api/v1/instance/peers. --- mastoapi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 8d61681..14dd251 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2256,6 +2256,15 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, status = HTTP_STATUS_OK; } else + if (strcmp(cmd, "/v1/instance/peers") == 0) { /** **/ + /* get the collected inbox list as the instances "this domain is aware of" */ + xs *list = inbox_list(); + + *body = xs_json_dumps(list, 4); + *ctype = "application/json"; + status = HTTP_STATUS_OK; + } + else if (xs_startswith(cmd, "/v1/statuses/")) { /** **/ /* information about a status */ if (logged_in) { -- cgit From 0b4e8cac069d31de736137de08543ace912b728a Mon Sep 17 00:00:00 2001 From: default Date: Sat, 22 Mar 2025 08:39:04 +0100 Subject: mastoapi: fixed instance peers to return only the domains. --- mastoapi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 14dd251..7b1e0ad 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2259,8 +2259,18 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (strcmp(cmd, "/v1/instance/peers") == 0) { /** **/ /* get the collected inbox list as the instances "this domain is aware of" */ xs *list = inbox_list(); + xs *peers = xs_list_new(); + const char *inbox; - *body = xs_json_dumps(list, 4); + xs_list_foreach(list, inbox) { + xs *l = xs_split(inbox, "/"); + const char *domain = xs_list_get(l, 2); + + if (xs_is_string(domain)) + peers = xs_list_append(peers, domain); + } + + *body = xs_json_dumps(peers, 4); *ctype = "application/json"; status = HTTP_STATUS_OK; } -- cgit From 877434218ffca350eb918fd47dfe81f29f2605ae Mon Sep 17 00:00:00 2001 From: default Date: Wed, 2 Apr 2025 09:01:31 +0200 Subject: mastoapi: added support for scheduled posts. --- mastoapi.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 7b1e0ad..d93afc5 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2726,14 +2726,24 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, msg = xs_dict_set(msg, "summary", summary); } - /* store */ - timeline_add(&snac, xs_dict_get(msg, "id"), msg); + /* scheduled? */ + const char *scheduled_at = xs_dict_get(args, "scheduled_at"); - /* 'Create' message */ - xs *c_msg = msg_create(&snac, msg); - enqueue_message(&snac, c_msg); + if (xs_is_string(scheduled_at) && *scheduled_at) { + msg = xs_dict_set(msg, "published", scheduled_at); - timeline_touch(&snac); + schedule_add(&snac, xs_dict_get(msg, "id"), msg); + } + else { + /* store */ + timeline_add(&snac, xs_dict_get(msg, "id"), msg); + + /* 'Create' message */ + xs *c_msg = msg_create(&snac, msg); + enqueue_message(&snac, c_msg); + + timeline_touch(&snac); + } /* convert to a mastodon status as a response code */ xs *st = mastoapi_status(&snac, msg); -- cgit From ec21e1596ab285813d5774224dfed77cbb30d23e Mon Sep 17 00:00:00 2001 From: green Date: Thu, 24 Apr 2025 15:49:55 +0200 Subject: mastoapi: support lists for users --- data.c | 3 ++- mastoapi.c | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 16 deletions(-) (limited to 'mastoapi.c') diff --git a/data.c b/data.c index 88f1921..0d1bbc6 100644 --- a/data.c +++ b/data.c @@ -2265,7 +2265,8 @@ xs_val *list_maint(snac *user, const char *list, int op) xs *l2 = xs_split(v2, "/"); /* return [ list_id, list_title ] */ - l = xs_list_append(l, xs_list_append(xs_list_new(), xs_list_get(l2, -1), title)); + xs *tmp_list = xs_list_append(xs_list_new(), xs_list_get(l2, -1), title); + l = xs_list_append(l, tmp_list); } } } diff --git a/mastoapi.c b/mastoapi.c index d93afc5..bea835c 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1500,6 +1500,37 @@ xs_str *timeline_link_header(const char *endpoint, xs_list *timeline) } +xs_list *mastoapi_account_lists(snac *user, const char *uid) +/* returns the list of list an user is in */ +{ + xs_list *out = xs_list_new(); + xs *actor_md5 = uid ? xs_md5_hex(uid, strlen(uid)) : NULL; + xs *lol = list_maint(user, NULL, 0); + + const xs_list *li; + xs_list_foreach(lol, li) { + const char *list_id = xs_list_get(li, 0); + const char *list_title = xs_list_get(li, 1); + if (uid) { + xs *users = list_content(user, list_id, NULL, 0); + if (xs_list_in(users, actor_md5) == -1) + continue; + } + + xs *d = xs_dict_new(); + + d = xs_dict_append(d, "id", list_id); + d = xs_dict_append(d, "title", list_title); + d = xs_dict_append(d, "replies_policy", "list"); + d = xs_dict_append(d, "exclusive", xs_stock(XSTYPE_FALSE)); + + out = xs_list_append(out, d); + } + + return out; +} + + int mastoapi_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype, xs_str **link) { @@ -1723,6 +1754,10 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (strcmp(opt, "followers") == 0) { out = xs_list_new(); } + else + if (strcmp(opt, "lists") == 0) { + out = mastoapi_account_lists(&snac1, uid); + } user_free(&snac2); } @@ -1744,6 +1779,10 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* implement empty response so apps like Tokodon don't show an error */ out = xs_list_new(); } + else + if (strcmp(opt, "lists") == 0) { + out = mastoapi_account_lists(&snac1, uid); + } } } @@ -1975,21 +2014,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, else if (strcmp(cmd, "/v1/lists") == 0) { /** list of lists **/ if (logged_in) { - xs *lol = list_maint(&snac1, NULL, 0); - xs *l = xs_list_new(); - int c = 0; - const xs_list *li; - - while (xs_list_next(lol, &li, &c)) { - xs *d = xs_dict_new(); - - d = xs_dict_append(d, "id", xs_list_get(li, 0)); - d = xs_dict_append(d, "title", xs_list_get(li, 1)); - d = xs_dict_append(d, "replies_policy", "list"); - d = xs_dict_append(d, "exclusive", xs_stock(XSTYPE_FALSE)); - - l = xs_list_append(l, d); - } + xs *l = mastoapi_account_lists(&snac1, NULL); *body = xs_json_dumps(l, 4); *ctype = "application/json"; -- cgit From c1502ca381afa7490f081530c88a01061aad6701 Mon Sep 17 00:00:00 2001 From: green Date: Thu, 24 Apr 2025 16:19:34 +0200 Subject: mastoapi: fix md5 issues --- mastoapi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index bea835c..705a902 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1504,9 +1504,16 @@ xs_list *mastoapi_account_lists(snac *user, const char *uid) /* returns the list of list an user is in */ { xs_list *out = xs_list_new(); - xs *actor_md5 = uid ? xs_md5_hex(uid, strlen(uid)) : NULL; + xs *actor_md5 = NULL; xs *lol = list_maint(user, NULL, 0); + if (uid) { + if (!xs_is_hex(uid)) + actor_md5 = xs_md5_hex(uid, strlen(uid)); + else + actor_md5 = xs_dup(uid); + } + const xs_list *li; xs_list_foreach(lol, li) { const char *list_id = xs_list_get(li, 0); -- cgit From 2a353d2ffdd7a6235a8f1a04ef62bde77141f159 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 27 Apr 2025 17:16:39 +0200 Subject: Mastoapi: correctly communicate 'approve_followers'. --- mastoapi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 705a902..e6acb11 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1223,7 +1223,10 @@ void credentials_get(char **body, char **ctype, int *status, snac snac) acct = xs_dict_append(acct, "last_status_at", xs_dict_get(snac.config, "published")); acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio")); acct = xs_dict_append(acct, "url", snac.actor); - acct = xs_dict_append(acct, "locked", xs_stock(XSTYPE_FALSE)); + + acct = xs_dict_append(acct, "locked", + xs_stock(xs_is_true(xs_dict_get(snac.config, "approve_followers")) ? XSTYPE_TRUE : XSTYPE_FALSE)); + acct = xs_dict_append(acct, "bot", xs_stock(xs_is_true(bot) ? XSTYPE_TRUE : XSTYPE_FALSE)); acct = xs_dict_append(acct, "emojis", xs_stock(XSTYPE_LIST)); -- cgit From 8ae0089bdb3c246810013de5c9541072b2593f00 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 14 May 2025 08:48:15 +0200 Subject: mastoapi: Also process the types[] argument in notifications. --- mastoapi.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index e6acb11..6a22189 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1874,13 +1874,14 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (logged_in) { xs *l = notify_list(&snac1, 0, 64); xs *out = xs_list_new(); - const xs_dict *v; + const char *v; const xs_list *excl = xs_dict_get(args, "exclude_types[]"); + const xs_list *incl = xs_dict_get(args, "types[]"); const char *min_id = xs_dict_get(args, "min_id"); const char *max_id = xs_dict_get(args, "max_id"); const char *limit = xs_dict_get(args, "limit"); int limit_count = 0; - if (!xs_is_null(limit)) { + if (xs_is_string(limit)) { limit_count = atoi(limit); } @@ -1899,11 +1900,12 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, const char *utype = xs_dict_get(noti, "utype"); const char *objid = xs_dict_get(noti, "objid"); const char *id = xs_dict_get(noti, "id"); + const char *actid = xs_dict_get(noti, "actor"); xs *fid = xs_replace(id, ".", ""); xs *actor = NULL; xs *entry = NULL; - if (!valid_status(actor_get(xs_dict_get(noti, "actor"), &actor))) + if (!valid_status(actor_get(actid, &actor))) continue; if (objid != NULL && !valid_status(object_get(objid, &entry))) @@ -1944,7 +1946,11 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, continue; /* excluded type? */ - if (!xs_is_null(excl) && xs_list_in(excl, type) != -1) + if (xs_is_list(excl) && xs_list_in(excl, type) != -1) + continue; + + /* included type? */ + if (xs_is_list(incl) && xs_list_in(incl, type) == -1) continue; xs *mn = xs_dict_new(); @@ -1970,10 +1976,9 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } out = xs_list_append(out, mn); - if (!xs_is_null(limit)) { - if (--limit_count <= 0) - break; - } + + if (--limit_count <= 0) + break; } srv_debug(1, xs_fmt("mastoapi_notifications count %d", xs_list_len(out))); -- cgit From 0900f69f2a4d08086e60cd5d31beac73b65f25a7 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 18 May 2025 08:43:31 +0200 Subject: mastoapi: added endpoint /v1/follow_requests. --- mastoapi.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 6a22189..c216a0b 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2109,10 +2109,26 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } else if (strcmp(cmd, "/v1/follow_requests") == 0) { /** **/ - /* snac does not support optional follow confirmations */ - *body = xs_dup("[]"); - *ctype = "application/json"; - status = HTTP_STATUS_OK; + if (logged_in) { + xs *pend = pending_list(&snac1); + xs *resp = xs_list_new(); + const char *id; + + xs_list_foreach(pend, id) { + xs *actor = NULL; + + if (valid_status(object_get(id, &actor))) { + xs *acct = mastoapi_account(&snac1, actor); + + if (acct) + resp = xs_list_append(resp, acct); + } + } + + *body = xs_json_dumps(resp, 4); + *ctype = "application/json"; + status = HTTP_STATUS_OK; + } } else if (strcmp(cmd, "/v1/announcements") == 0) { /** **/ -- cgit From 31b0f750a8af530ac61a38938e453740996ba9d5 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 18 May 2025 09:11:40 +0200 Subject: mastoapi: added post endpoints for 'authorize' and 'reject' follow requests. --- mastoapi.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index c216a0b..7fa0078 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -3244,6 +3244,57 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, *ctype = "application/json"; status = HTTP_STATUS_OK; } + else + if (xs_startswith(cmd, "/v1/follow_requests")) { /** **/ + if (logged_in) { + /* "authorize" or "reject" */ + xs *rel = NULL; + xs *l = xs_split(cmd, "/"); + const char *md5 = xs_list_get(l, -2); + const char *s_cmd = xs_list_get(l, -1); + + if (xs_is_string(md5) && xs_is_string(s_cmd)) { + xs *actor = NULL; + + if (valid_status(object_get_by_md5(md5, &actor))) { + const char *actor_id = xs_dict_get(actor, "id"); + + if (strcmp(s_cmd, "authorize") == 0) { + xs *fwreq = pending_get(&snac, actor_id); + + if (fwreq != NULL) { + xs *reply = msg_accept(&snac, fwreq, actor_id); + + enqueue_message(&snac, reply); + + if (xs_is_null(xs_dict_get(fwreq, "published"))) { + xs *date = xs_str_utctime(0, ISO_DATE_SPEC); + fwreq = xs_dict_set(fwreq, "published", date); + } + + timeline_add(&snac, xs_dict_get(fwreq, "id"), fwreq); + + follower_add(&snac, actor_id); + + pending_del(&snac, actor_id); + rel = mastoapi_relationship(&snac, md5); + } + } + else + if (strcmp(s_cmd, "reject") == 0) { + pending_del(&snac, actor_id); + rel = mastoapi_relationship(&snac, md5); + } + } + } + + if (rel != NULL) { + *body = xs_json_dumps(rel, 4); + *ctype = "application/json"; + status = HTTP_STATUS_OK; + } + } + } else status = HTTP_STATUS_UNPROCESSABLE_CONTENT; -- cgit From 321f64ed70d039dea510c8a7d7aee7dc9577737a Mon Sep 17 00:00:00 2001 From: green Date: Mon, 19 May 2025 15:25:11 +0200 Subject: performance: use following_list_len in more places --- activitypub.c | 6 ++---- data.c | 2 +- mastoapi.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'mastoapi.c') diff --git a/activitypub.c b/activitypub.c index a7e133a..120b4a1 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3204,8 +3204,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, int total = 0; if (show_contact_metrics) { - xs *l = follower_list(&snac); - total = xs_list_len(l); + total = follower_list_len(&snac); } xs *id = xs_fmt("%s/%s", snac.actor, p_path); @@ -3216,8 +3215,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, int total = 0; if (show_contact_metrics) { - xs *l = following_list(&snac); - total = xs_list_len(l); + total = following_list_len(&snac); } xs *id = xs_fmt("%s/%s", snac.actor, p_path); diff --git a/data.c b/data.c index 482a29c..f9d27f9 100644 --- a/data.c +++ b/data.c @@ -1216,7 +1216,7 @@ int follower_check(snac *snac, const char *actor) int follower_list_len(snac *snac) -/* returns the number followers */ +/* returns the number of followers */ { xs *list = object_user_cache_list(snac, "followers", XS_ALL, 0); return xs_list_len(list); diff --git a/mastoapi.c b/mastoapi.c index 7fa0078..a7d9c34 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -680,10 +680,10 @@ xs_dict *mastoapi_account(snac *logged, const xs_dict *actor) /* does this user want to publish their contact metrics? */ if (xs_is_true(xs_dict_get(user.config, "show_contact_metrics"))) { - xs *fwing = following_list(&user); - xs *fwers = follower_list(&user); - xs *ni = xs_number_new(xs_list_len(fwing)); - xs *ne = xs_number_new(xs_list_len(fwers)); + int fwing = following_list_len(&user); + int fwers = follower_list_len(&user); + xs *ni = xs_number_new(fwing); + xs *ne = xs_number_new(fwers); acct = xs_dict_append(acct, "followers_count", ne); acct = xs_dict_append(acct, "following_count", ni); @@ -1309,10 +1309,10 @@ void credentials_get(char **body, char **ctype, int *status, snac snac) /* does this user want to publish their contact metrics? */ if (xs_is_true(xs_dict_get(snac.config, "show_contact_metrics"))) { - xs *fwing = following_list(&snac); - xs *fwers = follower_list(&snac); - xs *ni = xs_number_new(xs_list_len(fwing)); - xs *ne = xs_number_new(xs_list_len(fwers)); + int fwing = following_list_len(&snac); + int fwers = follower_list_len(&snac); + xs *ni = xs_number_new(fwing); + xs *ne = xs_number_new(fwers); acct = xs_dict_append(acct, "followers_count", ne); acct = xs_dict_append(acct, "following_count", ni); -- cgit