diff options
Diffstat (limited to 'html.c')
| -rw-r--r-- | html.c | 160 |
1 files changed, 153 insertions, 7 deletions
| @@ -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_io.h" | 5 | #include "xs_io.h" |
| @@ -221,7 +221,7 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, | |||
| 221 | anchored link to the people page instead of the actor url */ | 221 | anchored link to the people page instead of the actor url */ |
| 222 | if (fwer || fwing) { | 222 | if (fwer || fwing) { |
| 223 | xs *md5 = xs_md5_hex(actor_id, strlen(actor_id)); | 223 | xs *md5 = xs_md5_hex(actor_id, strlen(actor_id)); |
| 224 | href = xs_fmt("%s/people#%s", user->actor, md5); | 224 | href = xs_fmt("%s/people/%s", user->actor, md5); |
| 225 | } | 225 | } |
| 226 | } | 226 | } |
| 227 | 227 | ||
| @@ -2103,7 +2103,7 @@ xs_html *html_entry_controls(snac *user, const char *actor, | |||
| 2103 | xs_html_tag("p", NULL)); | 2103 | xs_html_tag("p", NULL)); |
| 2104 | } | 2104 | } |
| 2105 | 2105 | ||
| 2106 | { /** emoji react **/ | 2106 | if (!xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) { /** emoji react **/ |
| 2107 | /* the post textarea */ | 2107 | /* the post textarea */ |
| 2108 | xs *div_id = xs_fmt("%s_reply", md5); | 2108 | xs *div_id = xs_fmt("%s_reply", md5); |
| 2109 | xs *form_id = xs_fmt("%s_reply_form", md5); | 2109 | xs *form_id = xs_fmt("%s_reply_form", md5); |
| @@ -2355,7 +2355,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2355 | } | 2355 | } |
| 2356 | 2356 | ||
| 2357 | if (!read_only && (fwers || fwing)) | 2357 | if (!read_only && (fwers || fwing)) |
| 2358 | href = xs_fmt("%s/people#%s", user->actor, p); | 2358 | href = xs_fmt("%s/people/%s", user->actor, p); |
| 2359 | else | 2359 | else |
| 2360 | href = xs_dup(id); | 2360 | href = xs_dup(id); |
| 2361 | 2361 | ||
| @@ -2447,7 +2447,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2447 | 2447 | ||
| 2448 | /* add all emoji reacts */ | 2448 | /* add all emoji reacts */ |
| 2449 | int is_emoji = 0; | 2449 | int is_emoji = 0; |
| 2450 | { | 2450 | if (!xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) { |
| 2451 | int c = 0; | 2451 | int c = 0; |
| 2452 | const xs_dict *k; | 2452 | const xs_dict *k; |
| 2453 | xs *ls = xs_list_new(); | 2453 | xs *ls = xs_list_new(); |
| @@ -2460,6 +2460,10 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2460 | const char *content = xs_dict_get(m, "content"); | 2460 | const char *content = xs_dict_get(m, "content"); |
| 2461 | const char *actor = xs_dict_get(m, "actor"); | 2461 | const char *actor = xs_dict_get(m, "actor"); |
| 2462 | const xs_list *contentl = xs_dict_get(sfrl, content); | 2462 | const xs_list *contentl = xs_dict_get(sfrl, content); |
| 2463 | |||
| 2464 | if ((user && is_muted(user, actor)) || is_instance_blocked(actor)) | ||
| 2465 | continue; | ||
| 2466 | |||
| 2463 | xs *actors = xs_list_new(); | 2467 | xs *actors = xs_list_new(); |
| 2464 | actors = xs_list_append(actors, actor); | 2468 | actors = xs_list_append(actors, actor); |
| 2465 | char me = actor && user && strcmp(actor, user->actor) == 0; | 2469 | char me = actor && user && strcmp(actor, user->actor) == 0; |
| @@ -3856,6 +3860,108 @@ xs_str *html_people(snac *user) | |||
| 3856 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); | 3860 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); |
| 3857 | } | 3861 | } |
| 3858 | 3862 | ||
| 3863 | /* Filter list to display only posts by actor. We'll probably show | ||
| 3864 | fewer than show posts. Should we try harder to find some? */ | ||
| 3865 | xs_str *html_people_one(snac *user, const char *actor, const xs_list *list, | ||
| 3866 | int skip, int show, int show_more, const char *page) | ||
| 3867 | { | ||
| 3868 | const char *proxy = NULL; | ||
| 3869 | xs_list *p = (xs_list *)list; | ||
| 3870 | const char *v; | ||
| 3871 | |||
| 3872 | if (xs_is_true(xs_dict_get(srv_config, "proxy_media"))) | ||
| 3873 | proxy = user->actor; | ||
| 3874 | |||
| 3875 | xs_html *body = html_user_body(user, 0); | ||
| 3876 | |||
| 3877 | xs_html *lists = xs_html_tag("div", | ||
| 3878 | xs_html_attr("class", "snac-posts")); | ||
| 3879 | |||
| 3880 | xs *foll = xs_list_append(xs_list_new(), actor); | ||
| 3881 | |||
| 3882 | xs_html_add(lists, | ||
| 3883 | html_people_list(user, foll, L("Contact's posts"), "p", proxy)); | ||
| 3884 | |||
| 3885 | xs_html_add(body, lists); | ||
| 3886 | |||
| 3887 | while (xs_list_iter(&p, &v)) { | ||
| 3888 | xs *msg = NULL; | ||
| 3889 | int status; | ||
| 3890 | |||
| 3891 | status = timeline_get_by_md5(user, v, &msg); | ||
| 3892 | |||
| 3893 | if (!valid_status(status)) | ||
| 3894 | continue; | ||
| 3895 | |||
| 3896 | const char *id = xs_dict_get(msg, "id"); | ||
| 3897 | const char *by = get_atto(msg); | ||
| 3898 | xs *actor_md5 = NULL; | ||
| 3899 | xs_list *boosts = NULL; | ||
| 3900 | xs_list *likes = NULL; | ||
| 3901 | xs_list *reacts = NULL; | ||
| 3902 | /* Besides actor's posts, also show actor's boosts, and also | ||
| 3903 | posts by user with likes or reacts by actor. I.e., any | ||
| 3904 | actor's actions that user could have seen in the timeline | ||
| 3905 | or in notifications. */ | ||
| 3906 | if (!(by && strcmp(actor, by) == 0) && | ||
| 3907 | xs_list_in((boosts = object_announces(id)), | ||
| 3908 | (actor_md5 = xs_md5_hex(actor, strlen(actor)))) == -1 && | ||
| 3909 | (!(by && strcmp(user->actor, by) == 0) || | ||
| 3910 | (xs_list_in((likes = object_likes(id)), actor_md5) == -1 && | ||
| 3911 | xs_list_in((reacts = object_get_emoji_reacts(id)), actor_md5) == -1))) | ||
| 3912 | continue; | ||
| 3913 | |||
| 3914 | xs_html *entry = html_entry(user, msg, 0, 0, v, 1); | ||
| 3915 | |||
| 3916 | if (entry != NULL) | ||
| 3917 | xs_html_add(lists, | ||
| 3918 | entry); | ||
| 3919 | } | ||
| 3920 | |||
| 3921 | if (show_more) { | ||
| 3922 | xs *m = NULL; | ||
| 3923 | xs *m10 = NULL; | ||
| 3924 | xs *ss = xs_fmt("skip=%d&show=%d", skip + show, show); | ||
| 3925 | |||
| 3926 | xs *url = xs_dup(user == NULL ? srv_baseurl : user->actor); | ||
| 3927 | |||
| 3928 | if (page != NULL) | ||
| 3929 | url = xs_str_cat(url, page); | ||
| 3930 | |||
| 3931 | if (xs_str_in(url, "?") != -1) | ||
| 3932 | m = xs_fmt("%s&%s", url, ss); | ||
| 3933 | else | ||
| 3934 | m = xs_fmt("%s?%s", url, ss); | ||
| 3935 | |||
| 3936 | m10 = xs_fmt("%s0", m); | ||
| 3937 | |||
| 3938 | xs_html *more_links = xs_html_tag("p", | ||
| 3939 | xs_html_tag("a", | ||
| 3940 | xs_html_attr("href", url), | ||
| 3941 | xs_html_attr("name", "snac-more"), | ||
| 3942 | xs_html_text(L("Back to top"))), | ||
| 3943 | xs_html_text(" - "), | ||
| 3944 | xs_html_tag("a", | ||
| 3945 | xs_html_attr("href", m), | ||
| 3946 | xs_html_attr("name", "snac-more"), | ||
| 3947 | xs_html_text(L("More..."))), | ||
| 3948 | xs_html_text(" - "), | ||
| 3949 | xs_html_tag("a", | ||
| 3950 | xs_html_attr("href", m10), | ||
| 3951 | xs_html_attr("name", "snac-more"), | ||
| 3952 | xs_html_text(L("More (x 10)...")))); | ||
| 3953 | |||
| 3954 | xs_html_add(body, | ||
| 3955 | more_links); | ||
| 3956 | } | ||
| 3957 | |||
| 3958 | xs_html *html = xs_html_tag("html", | ||
| 3959 | html_user_head(user, NULL, NULL), | ||
| 3960 | xs_html_add(body, | ||
| 3961 | html_footer(user))); | ||
| 3962 | |||
| 3963 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); | ||
| 3964 | } | ||
| 3859 | 3965 | ||
| 3860 | xs_str *html_notifications(snac *user, int skip, int show) | 3966 | xs_str *html_notifications(snac *user, int skip, int show) |
| 3861 | { | 3967 | { |
| @@ -3924,6 +4030,9 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 3924 | if (xs_is_string(id2) && xs_set_add(&rep, id2) != 1) | 4030 | if (xs_is_string(id2) && xs_set_add(&rep, id2) != 1) |
| 3925 | continue; | 4031 | continue; |
| 3926 | 4032 | ||
| 4033 | if (strcmp(type, "EmojiReact") == 0 && xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) | ||
| 4034 | continue; | ||
| 4035 | |||
| 3927 | object_get(id, &obj); | 4036 | object_get(id, &obj); |
| 3928 | 4037 | ||
| 3929 | const char *msg_id = NULL; | 4038 | const char *msg_id = NULL; |
| @@ -4271,8 +4380,12 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4271 | cache = 0; | 4380 | cache = 0; |
| 4272 | 4381 | ||
| 4273 | int skip = 0; | 4382 | int skip = 0; |
| 4383 | const char *max_show_default = "50"; | ||
| 4384 | int max_show = xs_number_get(xs_dict_get_def(srv_config, "max_timeline_entries", | ||
| 4385 | max_show_default)); | ||
| 4274 | int def_show = xs_number_get(xs_dict_get_def(srv_config, "def_timeline_entries", | 4386 | int def_show = xs_number_get(xs_dict_get_def(srv_config, "def_timeline_entries", |
| 4275 | xs_dict_get_def(srv_config, "max_timeline_entries", "50"))); | 4387 | xs_dict_get_def(srv_config, "max_timeline_entries", |
| 4388 | max_show_default))); | ||
| 4276 | int show = def_show; | 4389 | int show = def_show; |
| 4277 | 4390 | ||
| 4278 | if ((v = xs_dict_get(q_vars, "skip")) != NULL) | 4391 | if ((v = xs_dict_get(q_vars, "skip")) != NULL) |
| @@ -4298,6 +4411,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4298 | /* a show of 0 has no sense */ | 4411 | /* a show of 0 has no sense */ |
| 4299 | if (show == 0) | 4412 | if (show == 0) |
| 4300 | show = def_show; | 4413 | show = def_show; |
| 4414 | if (show > max_show) | ||
| 4415 | show = max_show; | ||
| 4301 | 4416 | ||
| 4302 | if (p_path == NULL) { /** public timeline **/ | 4417 | if (p_path == NULL) { /** public timeline **/ |
| 4303 | xs *h = xs_str_localtime(0, "%Y-%m.html"); | 4418 | xs *h = xs_str_localtime(0, "%Y-%m.html"); |
| @@ -4415,7 +4530,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4415 | actor_add(actor, actor_obj); | 4530 | actor_add(actor, actor_obj); |
| 4416 | 4531 | ||
| 4417 | /* create a people list with only one element */ | 4532 | /* create a people list with only one element */ |
| 4418 | l = xs_list_append(xs_list_new(), actor); | 4533 | l = xs_list_append(l, actor); |
| 4419 | 4534 | ||
| 4420 | xs *title = xs_fmt(L("Search results for account %s"), q); | 4535 | xs *title = xs_fmt(L("Search results for account %s"), q); |
| 4421 | 4536 | ||
| @@ -4555,6 +4670,37 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4555 | } | 4670 | } |
| 4556 | } | 4671 | } |
| 4557 | else | 4672 | else |
| 4673 | if (xs_startswith(p_path, "people/")) { /** a single actor **/ | ||
| 4674 | if (!login(&snac, req)) { | ||
| 4675 | *body = xs_dup(uid); | ||
| 4676 | status = HTTP_STATUS_UNAUTHORIZED; | ||
| 4677 | } | ||
| 4678 | else { | ||
| 4679 | xs *actor_dict = NULL; | ||
| 4680 | const char *actor_id = NULL; | ||
| 4681 | xs *actor = NULL; | ||
| 4682 | xs_list *page_lst = xs_split_n(p_path, "?", 2); | ||
| 4683 | xs *page = xs_str_cat(xs_str_new("/"), xs_list_get(page_lst, 0)); | ||
| 4684 | xs_list *l = xs_split_n(page, "/", 3); | ||
| 4685 | const char *actor_md5 = xs_list_get(l, 2); | ||
| 4686 | |||
| 4687 | if (valid_status(object_get_by_md5(actor_md5, &actor_dict)) && | ||
| 4688 | (actor_id = xs_dict_get(actor_dict, "id")) != NULL && | ||
| 4689 | valid_status(actor_get(actor_id, &actor))) { | ||
| 4690 | int more = 0; | ||
| 4691 | xs *list = timeline_simple_list(&snac, "private", skip, show, &more); | ||
| 4692 | |||
| 4693 | *body = html_people_one(&snac, actor_id, list, skip, show, more, page); | ||
| 4694 | *b_size = strlen(*body); | ||
| 4695 | status = HTTP_STATUS_OK; | ||
| 4696 | } | ||
| 4697 | else { | ||
| 4698 | *body = xs_dup(uid); | ||
| 4699 | status = HTTP_STATUS_NOT_FOUND; | ||
| 4700 | } | ||
| 4701 | } | ||
| 4702 | } | ||
| 4703 | else | ||
| 4558 | if (strcmp(p_path, "notifications") == 0) { /** the list of notifications **/ | 4704 | if (strcmp(p_path, "notifications") == 0) { /** the list of notifications **/ |
| 4559 | if (!login(&snac, req)) { | 4705 | if (!login(&snac, req)) { |
| 4560 | *body = xs_dup(uid); | 4706 | *body = xs_dup(uid); |