diff options
| -rw-r--r-- | RELEASE_NOTES.md | 4 | ||||
| -rw-r--r-- | TODO.md | 14 | ||||
| -rw-r--r-- | activitypub.c | 19 | ||||
| -rw-r--r-- | data.c | 6 | ||||
| -rw-r--r-- | html.c | 83 | ||||
| -rw-r--r-- | httpd.c | 6 | ||||
| -rw-r--r-- | snac.h | 7 |
7 files changed, 95 insertions, 44 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b8ee714..72e1d77 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md | |||
| @@ -2,12 +2,16 @@ | |||
| 2 | 2 | ||
| 3 | ## 2.48 | 3 | ## 2.48 |
| 4 | 4 | ||
| 5 | New instance page, that show all posts by users in the same instance (like the public instance timeline, but interactive). This will help building communities. | ||
| 6 | |||
| 5 | Follower-only replies to unknown users are not shown in timelines. | 7 | Follower-only replies to unknown users are not shown in timelines. |
| 6 | 8 | ||
| 7 | Added verification of metadata links: if the linked page contains a link back to the snac user with a rel="me" attribute, it's marked as verified. | 9 | Added verification of metadata links: if the linked page contains a link back to the snac user with a rel="me" attribute, it's marked as verified. |
| 8 | 10 | ||
| 9 | Added a profile-page relation to links in webfinger responses (contributed by khm). | 11 | Added a profile-page relation to links in webfinger responses (contributed by khm). |
| 10 | 12 | ||
| 13 | Fixed some regressions and a crash. | ||
| 14 | |||
| 11 | ## 2.47 | 15 | ## 2.47 |
| 12 | 16 | ||
| 13 | Added pagination to the notification page. | 17 | Added pagination to the notification page. |
| @@ -14,14 +14,16 @@ Important: deleting a follower should do more that just delete the object, see h | |||
| 14 | 14 | ||
| 15 | ## Wishlist | 15 | ## Wishlist |
| 16 | 16 | ||
| 17 | Add support for rel="me" links, see https://codeberg.org/grunfink/snac2/issues/124 and https://streetpass.social | ||
| 18 | |||
| 19 | Hide followers-only replies to unknown accounts, see https://codeberg.org/grunfink/snac2/issues/123 | ||
| 20 | |||
| 21 | Integrate "Ability to federate with hidden networks" see https://codeberg.org/grunfink/snac2/issues/93 | 17 | Integrate "Ability to federate with hidden networks" see https://codeberg.org/grunfink/snac2/issues/93 |
| 22 | 18 | ||
| 23 | Integrate "Added handling for International Domain Names" PR https://codeberg.org/grunfink/snac2/pulls/104 | 19 | Integrate "Added handling for International Domain Names" PR https://codeberg.org/grunfink/snac2/pulls/104 |
| 24 | 20 | ||
| 21 | Consider implementing the rejection of activities from recently-created accounts to mitigate spam, see https://akkoma.dev/AkkomaGang/akkoma/src/branch/develop/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex | ||
| 22 | |||
| 23 | Consider discarding posts by content using string or regex to mitigate spam. | ||
| 24 | |||
| 25 | Consider adding milter-like support to reject posts to mitigate spam. | ||
| 26 | |||
| 25 | Do something about Akkoma and Misskey's quoted replies (they use the `quoteUrl` field instead of `inReplyTo`). | 27 | Do something about Akkoma and Misskey's quoted replies (they use the `quoteUrl` field instead of `inReplyTo`). |
| 26 | 28 | ||
| 27 | Add more CSS classes according to https://comam.es/snac/grunfink/p/1705598619.090050 | 29 | Add more CSS classes according to https://comam.es/snac/grunfink/p/1705598619.090050 |
| @@ -301,3 +303,7 @@ Add a flag to make accounts private, i.e., they don't expose any content from th | |||
| 301 | Fix duplicate mentions, see https://codeberg.org/grunfink/snac2/issues/115 (2024-02-14T09:51:01+0100). | 303 | Fix duplicate mentions, see https://codeberg.org/grunfink/snac2/issues/115 (2024-02-14T09:51:01+0100). |
| 302 | 304 | ||
| 303 | Change HTML metadata information to the post info instead of user info, see https://codeberg.org/grunfink/snac2/issues/116 (2024-02-14T09:51:22+0100). | 305 | Change HTML metadata information to the post info instead of user info, see https://codeberg.org/grunfink/snac2/issues/116 (2024-02-14T09:51:22+0100). |
| 306 | |||
| 307 | Add support for rel="me" links, see https://codeberg.org/grunfink/snac2/issues/124 and https://streetpass.social (2024-02-22T12:40:58+0100). | ||
| 308 | |||
| 309 | Hide followers-only replies to unknown accounts, see https://codeberg.org/grunfink/snac2/issues/123 (2024-02-22T12:40:58+0100). | ||
diff --git a/activitypub.c b/activitypub.c index e389915..d8f748e 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -1955,9 +1955,12 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1955 | if (xs_type(object) == XSTYPE_DICT) | 1955 | if (xs_type(object) == XSTYPE_DICT) |
| 1956 | object = xs_dict_get(object, "id"); | 1956 | object = xs_dict_get(object, "id"); |
| 1957 | 1957 | ||
| 1958 | timeline_admire(snac, object, actor, 1); | 1958 | if (timeline_admire(snac, object, actor, 1) == 201) { |
| 1959 | snac_log(snac, xs_fmt("new 'Like' %s %s", actor, object)); | 1959 | snac_log(snac, xs_fmt("new 'Like' %s %s", actor, object)); |
| 1960 | do_notify = 1; | 1960 | do_notify = 1; |
| 1961 | } | ||
| 1962 | else | ||
| 1963 | snac_log(snac, xs_fmt("repeated 'Like' from %s to %s", actor, object)); | ||
| 1961 | } | 1964 | } |
| 1962 | else | 1965 | else |
| 1963 | if (strcmp(type, "Announce") == 0) { /** **/ | 1966 | if (strcmp(type, "Announce") == 0) { /** **/ |
| @@ -1983,9 +1986,13 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1983 | xs *who_o = NULL; | 1986 | xs *who_o = NULL; |
| 1984 | 1987 | ||
| 1985 | if (valid_status(actor_request(snac, who, &who_o))) { | 1988 | if (valid_status(actor_request(snac, who, &who_o))) { |
| 1986 | timeline_admire(snac, object, actor, 0); | 1989 | if (timeline_admire(snac, object, actor, 0) == 201) { |
| 1987 | snac_log(snac, xs_fmt("new 'Announce' %s %s", actor, object)); | 1990 | snac_log(snac, xs_fmt("new 'Announce' %s %s", actor, object)); |
| 1988 | do_notify = 1; | 1991 | do_notify = 1; |
| 1992 | } | ||
| 1993 | else | ||
| 1994 | snac_log(snac, xs_fmt("repeated 'Announce' from %s to %s", | ||
| 1995 | actor, object)); | ||
| 1989 | } | 1996 | } |
| 1990 | else | 1997 | else |
| 1991 | snac_debug(snac, 1, xs_fmt("dropped 'Announce' on actor request error %s", who)); | 1998 | snac_debug(snac, 1, xs_fmt("dropped 'Announce' on actor request error %s", who)); |
| @@ -1107,7 +1107,7 @@ int timeline_add(snac *snac, const char *id, const xs_dict *o_msg) | |||
| 1107 | } | 1107 | } |
| 1108 | 1108 | ||
| 1109 | 1109 | ||
| 1110 | void timeline_admire(snac *snac, const char *id, const char *admirer, int like) | 1110 | int timeline_admire(snac *snac, const char *id, const char *admirer, int like) |
| 1111 | /* updates a timeline entry with a new admiration */ | 1111 | /* updates a timeline entry with a new admiration */ |
| 1112 | { | 1112 | { |
| 1113 | /* if we are admiring this, add to both timelines */ | 1113 | /* if we are admiring this, add to both timelines */ |
| @@ -1116,10 +1116,12 @@ void timeline_admire(snac *snac, const char *id, const char *admirer, int like) | |||
| 1116 | object_user_cache_add(snac, id, "private"); | 1116 | object_user_cache_add(snac, id, "private"); |
| 1117 | } | 1117 | } |
| 1118 | 1118 | ||
| 1119 | object_admire(id, admirer, like); | 1119 | int ret = object_admire(id, admirer, like); |
| 1120 | 1120 | ||
| 1121 | snac_debug(snac, 1, xs_fmt("timeline_admire (%s) %s %s", | 1121 | snac_debug(snac, 1, xs_fmt("timeline_admire (%s) %s %s", |
| 1122 | like ? "Like" : "Announce", id, admirer)); | 1122 | like ? "Like" : "Announce", id, admirer)); |
| 1123 | |||
| 1124 | return ret; | ||
| 1123 | } | 1125 | } |
| 1124 | 1126 | ||
| 1125 | 1127 | ||
| @@ -646,7 +646,7 @@ xs_html *html_user_head(snac *user, char *desc) | |||
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | 648 | ||
| 649 | static xs_html *html_user_body(snac *user, int local) | 649 | static xs_html *html_user_body(snac *user, int read_only) |
| 650 | { | 650 | { |
| 651 | xs_html *body = xs_html_tag("body", NULL); | 651 | xs_html *body = xs_html_tag("body", NULL); |
| 652 | 652 | ||
| @@ -667,7 +667,7 @@ static xs_html *html_user_body(snac *user, int local) | |||
| 667 | xs_html_attr("class", "snac-avatar"), | 667 | xs_html_attr("class", "snac-avatar"), |
| 668 | xs_html_attr("alt", ""))); | 668 | xs_html_attr("alt", ""))); |
| 669 | 669 | ||
| 670 | if (local) { | 670 | if (read_only) { |
| 671 | xs *rss_url = xs_fmt("%s.rss", user->actor); | 671 | xs *rss_url = xs_fmt("%s.rss", user->actor); |
| 672 | xs *admin_url = xs_fmt("%s/admin", user->actor); | 672 | xs *admin_url = xs_fmt("%s/admin", user->actor); |
| 673 | 673 | ||
| @@ -698,6 +698,8 @@ static xs_html *html_user_body(snac *user, int local) | |||
| 698 | xs *admin_url = xs_fmt("%s/admin", user->actor); | 698 | xs *admin_url = xs_fmt("%s/admin", user->actor); |
| 699 | xs *notify_url = xs_fmt("%s/notifications", user->actor); | 699 | xs *notify_url = xs_fmt("%s/notifications", user->actor); |
| 700 | xs *people_url = xs_fmt("%s/people", user->actor); | 700 | xs *people_url = xs_fmt("%s/people", user->actor); |
| 701 | xs *instance_url = xs_fmt("%s/instance", user->actor); | ||
| 702 | |||
| 701 | xs_html_add(top_nav, | 703 | xs_html_add(top_nav, |
| 702 | xs_html_tag("a", | 704 | xs_html_tag("a", |
| 703 | xs_html_attr("href", user->actor), | 705 | xs_html_attr("href", user->actor), |
| @@ -714,7 +716,11 @@ static xs_html *html_user_body(snac *user, int local) | |||
| 714 | xs_html_text(" - "), | 716 | xs_html_text(" - "), |
| 715 | xs_html_tag("a", | 717 | xs_html_tag("a", |
| 716 | xs_html_attr("href", people_url), | 718 | xs_html_attr("href", people_url), |
| 717 | xs_html_text(L("people")))); | 719 | xs_html_text(L("people"))), |
| 720 | xs_html_text(" - "), | ||
| 721 | xs_html_tag("a", | ||
| 722 | xs_html_attr("href", instance_url), | ||
| 723 | xs_html_text(L("instance")))); | ||
| 718 | } | 724 | } |
| 719 | 725 | ||
| 720 | xs_html_add(body, | 726 | xs_html_add(body, |
| @@ -724,7 +730,7 @@ static xs_html *html_user_body(snac *user, int local) | |||
| 724 | xs_html *top_user = xs_html_tag("div", | 730 | xs_html *top_user = xs_html_tag("div", |
| 725 | xs_html_attr("class", "h-card snac-top-user")); | 731 | xs_html_attr("class", "h-card snac-top-user")); |
| 726 | 732 | ||
| 727 | if (local) { | 733 | if (read_only) { |
| 728 | char *header = xs_dict_get(user->config, "header"); | 734 | char *header = xs_dict_get(user->config, "header"); |
| 729 | if (header && *header) { | 735 | if (header && *header) { |
| 730 | xs_html_add(top_user, | 736 | xs_html_add(top_user, |
| @@ -749,7 +755,7 @@ static xs_html *html_user_body(snac *user, int local) | |||
| 749 | xs_html_attr("class", "snac-top-user-id"), | 755 | xs_html_attr("class", "snac-top-user-id"), |
| 750 | xs_html_text(handle))); | 756 | xs_html_text(handle))); |
| 751 | 757 | ||
| 752 | if (local) { | 758 | if (read_only) { |
| 753 | xs *es1 = encode_html(xs_dict_get(user->config, "bio")); | 759 | xs *es1 = encode_html(xs_dict_get(user->config, "bio")); |
| 754 | xs *bio1 = not_really_markdown(es1, NULL); | 760 | xs *bio1 = not_really_markdown(es1, NULL); |
| 755 | xs *tags = xs_list_new(); | 761 | xs *tags = xs_list_new(); |
| @@ -1306,7 +1312,7 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const | |||
| 1306 | } | 1312 | } |
| 1307 | 1313 | ||
| 1308 | 1314 | ||
| 1309 | xs_html *html_entry(snac *user, xs_dict *msg, int local, | 1315 | xs_html *html_entry(snac *user, xs_dict *msg, int read_only, |
| 1310 | int level, char *md5, int hide_children) | 1316 | int level, char *md5, int hide_children) |
| 1311 | { | 1317 | { |
| 1312 | char *id = xs_dict_get(msg, "id"); | 1318 | char *id = xs_dict_get(msg, "id"); |
| @@ -1315,7 +1321,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1315 | char *v; | 1321 | char *v; |
| 1316 | 1322 | ||
| 1317 | /* do not show non-public messages in the public timeline */ | 1323 | /* do not show non-public messages in the public timeline */ |
| 1318 | if ((local || !user) && !is_msg_public(msg)) | 1324 | if ((read_only || !user) && !is_msg_public(msg)) |
| 1319 | return NULL; | 1325 | return NULL; |
| 1320 | 1326 | ||
| 1321 | /* hidden? do nothing more for this conversation */ | 1327 | /* hidden? do nothing more for this conversation */ |
| @@ -1334,7 +1340,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1334 | xs_html_tag("div", | 1340 | xs_html_tag("div", |
| 1335 | xs_html_attr("class", "snac-origin"), | 1341 | xs_html_attr("class", "snac-origin"), |
| 1336 | xs_html_text(L("follows you"))), | 1342 | xs_html_text(L("follows you"))), |
| 1337 | html_msg_icon(local ? NULL : user, xs_dict_get(msg, "actor"), msg))); | 1343 | html_msg_icon(read_only ? NULL : user, xs_dict_get(msg, "actor"), msg))); |
| 1338 | } | 1344 | } |
| 1339 | else | 1345 | else |
| 1340 | if (!xs_match(type, "Note|Question|Page|Article|Video")) { | 1346 | if (!xs_match(type, "Note|Question|Page|Article|Video")) { |
| @@ -1446,7 +1452,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1446 | if (!xs_is_null(name)) { | 1452 | if (!xs_is_null(name)) { |
| 1447 | xs *href = NULL; | 1453 | xs *href = NULL; |
| 1448 | 1454 | ||
| 1449 | if (!local && user != NULL) | 1455 | if (!read_only && user != NULL) |
| 1450 | href = xs_fmt("%s/people#%s", user->actor, p); | 1456 | href = xs_fmt("%s/people#%s", user->actor, p); |
| 1451 | else | 1457 | else |
| 1452 | href = xs_dup(xs_dict_get(actor_r, "id")); | 1458 | href = xs_dup(xs_dict_get(actor_r, "id")); |
| @@ -1482,7 +1488,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1482 | } | 1488 | } |
| 1483 | 1489 | ||
| 1484 | xs_html_add(post_header, | 1490 | xs_html_add(post_header, |
| 1485 | html_msg_icon(local ? NULL : user, actor, msg)); | 1491 | html_msg_icon(read_only ? NULL : user, actor, msg)); |
| 1486 | 1492 | ||
| 1487 | /** post content **/ | 1493 | /** post content **/ |
| 1488 | 1494 | ||
| @@ -1510,7 +1516,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1510 | 1516 | ||
| 1511 | /* only show it when not in the public timeline and the config setting is "open" */ | 1517 | /* only show it when not in the public timeline and the config setting is "open" */ |
| 1512 | char *cw = xs_dict_get(user->config, "cw"); | 1518 | char *cw = xs_dict_get(user->config, "cw"); |
| 1513 | if (xs_is_null(cw) || local) | 1519 | if (xs_is_null(cw) || read_only) |
| 1514 | cw = ""; | 1520 | cw = ""; |
| 1515 | 1521 | ||
| 1516 | snac_content = xs_html_tag("details", | 1522 | snac_content = xs_html_tag("details", |
| @@ -1574,7 +1580,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1574 | 1580 | ||
| 1575 | xs_html *poll = xs_html_tag("div", NULL); | 1581 | xs_html *poll = xs_html_tag("div", NULL); |
| 1576 | 1582 | ||
| 1577 | if (local) | 1583 | if (read_only) |
| 1578 | closed = 1; /* non-identified page; show as closed */ | 1584 | closed = 1; /* non-identified page; show as closed */ |
| 1579 | else | 1585 | else |
| 1580 | if (xs_dict_get(msg, "closed")) | 1586 | if (xs_dict_get(msg, "closed")) |
| @@ -1795,7 +1801,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1795 | 1801 | ||
| 1796 | /** controls **/ | 1802 | /** controls **/ |
| 1797 | 1803 | ||
| 1798 | if (!local && user) { | 1804 | if (!read_only && user) { |
| 1799 | xs_html_add(entry, | 1805 | xs_html_add(entry, |
| 1800 | html_entry_controls(user, actor, msg, md5)); | 1806 | html_entry_controls(user, actor, msg, md5)); |
| 1801 | } | 1807 | } |
| @@ -1839,7 +1845,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int local, | |||
| 1839 | object_get_by_md5(cmd5, &chd); | 1845 | object_get_by_md5(cmd5, &chd); |
| 1840 | 1846 | ||
| 1841 | if (chd != NULL && xs_is_null(xs_dict_get(chd, "name"))) { | 1847 | if (chd != NULL && xs_is_null(xs_dict_get(chd, "name"))) { |
| 1842 | xs_html *che = html_entry(user, chd, local, level + 1, cmd5, hide_children); | 1848 | xs_html *che = html_entry(user, chd, read_only, level + 1, cmd5, hide_children); |
| 1843 | 1849 | ||
| 1844 | if (che != NULL) { | 1850 | if (che != NULL) { |
| 1845 | if (left > 3) | 1851 | if (left > 3) |
| @@ -1879,8 +1885,9 @@ xs_html *html_footer(void) | |||
| 1879 | } | 1885 | } |
| 1880 | 1886 | ||
| 1881 | 1887 | ||
| 1882 | xs_str *html_timeline(snac *user, const xs_list *list, int local, | 1888 | xs_str *html_timeline(snac *user, const xs_list *list, int read_only, |
| 1883 | int skip, int show, int show_more, char *tag) | 1889 | int skip, int show, int show_more, |
| 1890 | char *tag, char *page, int utl) | ||
| 1884 | /* returns the HTML for the timeline */ | 1891 | /* returns the HTML for the timeline */ |
| 1885 | { | 1892 | { |
| 1886 | xs_list *p = (xs_list *)list; | 1893 | xs_list *p = (xs_list *)list; |
| @@ -1903,7 +1910,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int local, | |||
| 1903 | 1910 | ||
| 1904 | if (user) { | 1911 | if (user) { |
| 1905 | head = html_user_head(user, desc); | 1912 | head = html_user_head(user, desc); |
| 1906 | body = html_user_body(user, local); | 1913 | body = html_user_body(user, read_only); |
| 1907 | } | 1914 | } |
| 1908 | else { | 1915 | else { |
| 1909 | head = html_instance_head(); | 1916 | head = html_instance_head(); |
| @@ -1914,7 +1921,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int local, | |||
| 1914 | head, | 1921 | head, |
| 1915 | body); | 1922 | body); |
| 1916 | 1923 | ||
| 1917 | if (user && !local) | 1924 | if (user && !read_only) |
| 1918 | xs_html_add(body, | 1925 | xs_html_add(body, |
| 1919 | html_top_controls(user)); | 1926 | html_top_controls(user)); |
| 1920 | 1927 | ||
| @@ -1932,7 +1939,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int local, | |||
| 1932 | xs *msg = NULL; | 1939 | xs *msg = NULL; |
| 1933 | int status; | 1940 | int status; |
| 1934 | 1941 | ||
| 1935 | if (user && !is_pinned_by_md5(user, v)) | 1942 | if (utl && user && !is_pinned_by_md5(user, v)) |
| 1936 | status = timeline_get_by_md5(user, v, &msg); | 1943 | status = timeline_get_by_md5(user, v, &msg); |
| 1937 | else | 1944 | else |
| 1938 | status = object_get_by_md5(v, &msg); | 1945 | status = object_get_by_md5(v, &msg); |
| @@ -1954,14 +1961,15 @@ xs_str *html_timeline(snac *user, const xs_list *list, int local, | |||
| 1954 | } | 1961 | } |
| 1955 | } | 1962 | } |
| 1956 | 1963 | ||
| 1957 | xs_html *entry = html_entry(user, msg, local, 0, v, user ? 0 : 1); | 1964 | xs_html *entry = html_entry(user, msg, read_only, 0, v, user ? 0 : 1); |
| 1958 | 1965 | ||
| 1959 | if (entry != NULL) | 1966 | if (entry != NULL) |
| 1960 | xs_html_add(posts, | 1967 | xs_html_add(posts, |
| 1961 | entry); | 1968 | entry); |
| 1962 | } | 1969 | } |
| 1963 | 1970 | ||
| 1964 | if (list && user && local) { | 1971 | if (list && user && read_only) { |
| 1972 | /** history **/ | ||
| 1965 | if (xs_type(xs_dict_get(srv_config, "disable_history")) != XSTYPE_TRUE) { | 1973 | if (xs_type(xs_dict_get(srv_config, "disable_history")) != XSTYPE_TRUE) { |
| 1966 | xs_html *ul = xs_html_tag("ul", NULL); | 1974 | xs_html *ul = xs_html_tag("ul", NULL); |
| 1967 | 1975 | ||
| @@ -2003,12 +2011,15 @@ xs_str *html_timeline(snac *user, const xs_list *list, int local, | |||
| 2003 | xs *m = NULL; | 2011 | xs *m = NULL; |
| 2004 | xs *ss = xs_fmt("skip=%d&show=%d", skip + show, show); | 2012 | xs *ss = xs_fmt("skip=%d&show=%d", skip + show, show); |
| 2005 | 2013 | ||
| 2014 | xs *url = page == NULL || user == NULL ? | ||
| 2015 | xs_dup(srv_baseurl) : xs_fmt("%s%s", user->actor, page); | ||
| 2016 | |||
| 2006 | if (tag) { | 2017 | if (tag) { |
| 2007 | t = xs_fmt("%s?t=%s", srv_baseurl, tag); | 2018 | t = xs_fmt("%s?t=%s", url, tag); |
| 2008 | m = xs_fmt("%s&%s", t, ss); | 2019 | m = xs_fmt("%s&%s", t, ss); |
| 2009 | } | 2020 | } |
| 2010 | else { | 2021 | else { |
| 2011 | t = xs_fmt("%s%s", user ? user->actor : srv_baseurl, local ? "" : "/admin"); | 2022 | t = xs_dup(url); |
| 2012 | m = xs_fmt("%s?%s", t, ss); | 2023 | m = xs_fmt("%s?%s", t, ss); |
| 2013 | } | 2024 | } |
| 2014 | 2025 | ||
| @@ -2401,7 +2412,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 2401 | xs *h = xs_str_localtime(0, "%Y-%m.html"); | 2412 | xs *h = xs_str_localtime(0, "%Y-%m.html"); |
| 2402 | 2413 | ||
| 2403 | if (xs_type(xs_dict_get(snac.config, "private")) == XSTYPE_TRUE) { | 2414 | if (xs_type(xs_dict_get(snac.config, "private")) == XSTYPE_TRUE) { |
| 2404 | *body = html_timeline(&snac, NULL, 1, 0, 0, 0, NULL); | 2415 | /** empty public timeline for private users **/ |
| 2416 | *body = html_timeline(&snac, NULL, 1, 0, 0, 0, NULL, "", 1); | ||
| 2405 | *b_size = strlen(*body); | 2417 | *b_size = strlen(*body); |
| 2406 | status = 200; | 2418 | status = 200; |
| 2407 | } | 2419 | } |
| @@ -2419,7 +2431,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 2419 | xs *pins = pinned_list(&snac); | 2431 | xs *pins = pinned_list(&snac); |
| 2420 | pins = xs_list_cat(pins, list); | 2432 | pins = xs_list_cat(pins, list); |
| 2421 | 2433 | ||
| 2422 | *body = html_timeline(&snac, pins, 1, skip, show, xs_list_len(next), NULL); | 2434 | *body = html_timeline(&snac, pins, 1, skip, show, xs_list_len(next), NULL, "", 1); |
| 2423 | 2435 | ||
| 2424 | *b_size = strlen(*body); | 2436 | *b_size = strlen(*body); |
| 2425 | status = 200; | 2437 | status = 200; |
| @@ -2456,7 +2468,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 2456 | xs *pins = pinned_list(&snac); | 2468 | xs *pins = pinned_list(&snac); |
| 2457 | pins = xs_list_cat(pins, list); | 2469 | pins = xs_list_cat(pins, list); |
| 2458 | 2470 | ||
| 2459 | *body = html_timeline(&snac, pins, 0, skip, show, xs_list_len(next), NULL); | 2471 | *body = html_timeline(&snac, pins, 0, skip, show, |
| 2472 | xs_list_len(next), NULL, "/admin", 1); | ||
| 2460 | 2473 | ||
| 2461 | *b_size = strlen(*body); | 2474 | *b_size = strlen(*body); |
| 2462 | status = 200; | 2475 | status = 200; |
| @@ -2491,6 +2504,22 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 2491 | } | 2504 | } |
| 2492 | } | 2505 | } |
| 2493 | else | 2506 | else |
| 2507 | if (strcmp(p_path, "instance") == 0) { /** instance timeline **/ | ||
| 2508 | if (!login(&snac, req)) { | ||
| 2509 | *body = xs_dup(uid); | ||
| 2510 | status = 401; | ||
| 2511 | } | ||
| 2512 | else { | ||
| 2513 | xs *list = timeline_instance_list(skip, show); | ||
| 2514 | xs *next = timeline_instance_list(skip + show, 1); | ||
| 2515 | |||
| 2516 | *body = html_timeline(&snac, list, 0, skip, show, | ||
| 2517 | xs_list_len(next), NULL, "/instance", 0); | ||
| 2518 | *b_size = strlen(*body); | ||
| 2519 | status = 200; | ||
| 2520 | } | ||
| 2521 | } | ||
| 2522 | else | ||
| 2494 | if (xs_startswith(p_path, "p/")) { /** a timeline with just one entry **/ | 2523 | if (xs_startswith(p_path, "p/")) { /** a timeline with just one entry **/ |
| 2495 | if (xs_type(xs_dict_get(snac.config, "private")) == XSTYPE_TRUE) | 2524 | if (xs_type(xs_dict_get(snac.config, "private")) == XSTYPE_TRUE) |
| 2496 | return 403; | 2525 | return 403; |
| @@ -2504,7 +2533,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 2504 | 2533 | ||
| 2505 | list = xs_list_append(list, md5); | 2534 | list = xs_list_append(list, md5); |
| 2506 | 2535 | ||
| 2507 | *body = html_timeline(&snac, list, 1, 0, 0, 0, NULL); | 2536 | *body = html_timeline(&snac, list, 1, 0, 0, 0, NULL, "", 1); |
| 2508 | *b_size = strlen(*body); | 2537 | *b_size = strlen(*body); |
| 2509 | status = 200; | 2538 | status = 200; |
| 2510 | } | 2539 | } |
| @@ -177,6 +177,7 @@ int server_get_handler(xs_dict *req, const char *q_path, | |||
| 177 | char *t = NULL; | 177 | char *t = NULL; |
| 178 | 178 | ||
| 179 | if (xs_type(q_vars) == XSTYPE_DICT && (t = xs_dict_get(q_vars, "t"))) { | 179 | if (xs_type(q_vars) == XSTYPE_DICT && (t = xs_dict_get(q_vars, "t"))) { |
| 180 | /** search by tag **/ | ||
| 180 | int skip = 0; | 181 | int skip = 0; |
| 181 | int show = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries")); | 182 | int show = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries")); |
| 182 | char *v; | 183 | char *v; |
| @@ -194,12 +195,13 @@ int server_get_handler(xs_dict *req, const char *q_path, | |||
| 194 | more = 1; | 195 | more = 1; |
| 195 | } | 196 | } |
| 196 | 197 | ||
| 197 | *body = html_timeline(NULL, tl, 0, skip, show, more, t); | 198 | *body = html_timeline(NULL, tl, 0, skip, show, more, t, NULL, 0); |
| 198 | } | 199 | } |
| 199 | else | 200 | else |
| 200 | if (xs_type(xs_dict_get(srv_config, "show_instance_timeline")) == XSTYPE_TRUE) { | 201 | if (xs_type(xs_dict_get(srv_config, "show_instance_timeline")) == XSTYPE_TRUE) { |
| 202 | /** instance timeline **/ | ||
| 201 | xs *tl = timeline_instance_list(0, 30); | 203 | xs *tl = timeline_instance_list(0, 30); |
| 202 | *body = html_timeline(NULL, tl, 0, 0, 0, 0, NULL); | 204 | *body = html_timeline(NULL, tl, 0, 0, 0, 0, NULL, NULL, 0); |
| 203 | } | 205 | } |
| 204 | else | 206 | else |
| 205 | *body = greeting_html(); | 207 | *body = greeting_html(); |
| @@ -133,7 +133,7 @@ int timeline_del(snac *snac, char *id); | |||
| 133 | xs_list *timeline_simple_list(snac *snac, const char *idx_name, int skip, int show); | 133 | xs_list *timeline_simple_list(snac *snac, const char *idx_name, int skip, int show); |
| 134 | xs_list *timeline_list(snac *snac, const char *idx_name, int skip, int show); | 134 | xs_list *timeline_list(snac *snac, const char *idx_name, int skip, int show); |
| 135 | int timeline_add(snac *snac, const char *id, const xs_dict *o_msg); | 135 | int timeline_add(snac *snac, const char *id, const xs_dict *o_msg); |
| 136 | void timeline_admire(snac *snac, const char *id, const char *admirer, int like); | 136 | int timeline_admire(snac *snac, const char *id, const char *admirer, int like); |
| 137 | 137 | ||
| 138 | xs_list *timeline_top_level(snac *snac, xs_list *list); | 138 | xs_list *timeline_top_level(snac *snac, xs_list *list); |
| 139 | xs_list *local_list(snac *snac, int max); | 139 | xs_list *local_list(snac *snac, int max); |
| @@ -296,8 +296,9 @@ xs_str *not_really_markdown(const char *content, xs_list **attach); | |||
| 296 | xs_str *sanitize(const char *content); | 296 | xs_str *sanitize(const char *content); |
| 297 | xs_str *encode_html(const char *str); | 297 | xs_str *encode_html(const char *str); |
| 298 | 298 | ||
| 299 | xs_str *html_timeline(snac *user, const xs_list *list, int local, | 299 | xs_str *html_timeline(snac *user, const xs_list *list, int read_only, |
| 300 | int skip, int show, int show_more, char *tag); | 300 | int skip, int show, int show_more, |
| 301 | char *tag, char *page, int utl); | ||
| 301 | 302 | ||
| 302 | int html_get_handler(const xs_dict *req, const char *q_path, | 303 | int html_get_handler(const xs_dict *req, const char *q_path, |
| 303 | char **body, int *b_size, char **ctype, xs_str **etag); | 304 | char **body, int *b_size, char **ctype, xs_str **etag); |