summaryrefslogtreecommitdiff
path: root/html.c
diff options
context:
space:
mode:
Diffstat (limited to 'html.c')
-rw-r--r--html.c160
1 files changed, 153 insertions, 7 deletions
diff --git a/html.c b/html.c
index 3e692bd..d5294cb 100644
--- a/html.c
+++ b/html.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_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? */
3865xs_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
3860xs_str *html_notifications(snac *user, int skip, int show) 3966xs_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);