summaryrefslogtreecommitdiff
path: root/html.c
diff options
context:
space:
mode:
Diffstat (limited to 'html.c')
-rw-r--r--html.c212
1 files changed, 156 insertions, 56 deletions
diff --git a/html.c b/html.c
index 46ef735..a251e21 100644
--- a/html.c
+++ b/html.c
@@ -113,9 +113,13 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date,
113 xs *name = actor_name(actor); 113 xs *name = actor_name(actor);
114 114
115 /* get the avatar */ 115 /* get the avatar */
116 if ((v = xs_dict_get(actor, "icon")) != NULL && 116 if ((v = xs_dict_get(actor, "icon")) != NULL) {
117 (v = xs_dict_get(v, "url")) != NULL) { 117 /* if it's a list (Peertube), get the first one */
118 avatar = xs_dup(v); 118 if (xs_type(v) == XSTYPE_LIST)
119 v = xs_list_get(v, 0);
120
121 if ((v = xs_dict_get(v, "url")) != NULL)
122 avatar = xs_dup(v);
119 } 123 }
120 124
121 if (avatar == NULL) 125 if (avatar == NULL)
@@ -245,7 +249,7 @@ xs_html *html_msg_icon(snac *user, char *actor_id, const xs_dict *msg)
245 xs *actor = NULL; 249 xs *actor = NULL;
246 xs_html *actor_icon = NULL; 250 xs_html *actor_icon = NULL;
247 251
248 if (actor_id && valid_status(actor_get(actor_id, &actor))) { 252 if (actor_id && valid_status(actor_get_refresh(user, actor_id, &actor))) {
249 char *date = NULL; 253 char *date = NULL;
250 char *udate = NULL; 254 char *udate = NULL;
251 char *url = NULL; 255 char *url = NULL;
@@ -273,7 +277,8 @@ xs_html *html_note(snac *user, char *summary,
273 char *edit_id, char *actor_id, 277 char *edit_id, char *actor_id,
274 xs_val *cw_yn, char *cw_text, 278 xs_val *cw_yn, char *cw_text,
275 xs_val *mnt_only, char *redir, 279 xs_val *mnt_only, char *redir,
276 char *in_reply_to, int poll) 280 char *in_reply_to, int poll,
281 char *att_file, char *att_alt_text)
277{ 282{
278 xs *action = xs_fmt("%s/admin/note", user->actor); 283 xs *action = xs_fmt("%s/admin/note", user->actor);
279 284
@@ -359,19 +364,37 @@ xs_html *html_note(snac *user, char *summary,
359 xs_html_attr("name", "edit_id"), 364 xs_html_attr("name", "edit_id"),
360 xs_html_attr("value", edit_id))); 365 xs_html_attr("value", edit_id)));
361 366
367 /* attachment controls */
368 xs_html *att;
369
362 xs_html_add(form, 370 xs_html_add(form,
363 xs_html_tag("p", NULL), 371 xs_html_tag("p", NULL),
364 xs_html_tag("details", 372 att = xs_html_tag("details",
365 xs_html_tag("summary", 373 xs_html_tag("summary",
366 xs_html_text(L("Attachment..."))), 374 xs_html_text(L("Attachment..."))),
367 xs_html_tag("p", NULL), 375 xs_html_tag("p", NULL)));
368 xs_html_sctag("input", 376
369 xs_html_attr("type", "file"), 377 if (att_file && *att_file)
370 xs_html_attr("name", "attach")), 378 xs_html_add(att,
371 xs_html_sctag("input", 379 xs_html_text(L("File:")),
372 xs_html_attr("type", "text"), 380 xs_html_sctag("input",
373 xs_html_attr("name", "alt_text"), 381 xs_html_attr("type", "text"),
374 xs_html_attr("placeholder", L("Attachment description"))))); 382 xs_html_attr("name", "attach_url"),
383 xs_html_attr("title", L("Clear this field to delete the attachment")),
384 xs_html_attr("value", att_file)));
385 else
386 xs_html_add(att,
387 xs_html_sctag("input",
388 xs_html_attr("type", "file"),
389 xs_html_attr("name", "attach")));
390
391 xs_html_add(att,
392 xs_html_text(" "),
393 xs_html_sctag("input",
394 xs_html_attr("type", "text"),
395 xs_html_attr("name", "alt_text"),
396 xs_html_attr("value", att_alt_text),
397 xs_html_attr("placeholder", L("Attachment description"))));
375 398
376 /* add poll controls */ 399 /* add poll controls */
377 if (poll) { 400 if (poll) {
@@ -551,7 +574,7 @@ static xs_html *html_instance_body(char *tag)
551} 574}
552 575
553 576
554xs_html *html_user_head(snac *user, char *desc) 577xs_html *html_user_head(snac *user, char *desc, char *url)
555{ 578{
556 xs_html *head = html_base_head(); 579 xs_html *head = html_base_head();
557 580
@@ -641,6 +664,13 @@ xs_html *html_user_head(snac *user, char *desc)
641 xs_html_attr("title", "RSS"), 664 xs_html_attr("title", "RSS"),
642 xs_html_attr("href", rss_url))); 665 xs_html_attr("href", rss_url)));
643 666
667 /* ActivityPub alternate link (actor id) */
668 xs_html_add(head,
669 xs_html_sctag("link",
670 xs_html_attr("rel", "alternate"),
671 xs_html_attr("type", "application/activity+json"),
672 xs_html_attr("href", url ? url : user->actor)));
673
644 return head; 674 return head;
645} 675}
646 676
@@ -756,7 +786,7 @@ static xs_html *html_user_body(snac *user, int read_only)
756 786
757 if (read_only) { 787 if (read_only) {
758 xs *es1 = encode_html(xs_dict_get(user->config, "bio")); 788 xs *es1 = encode_html(xs_dict_get(user->config, "bio"));
759 xs *bio1 = not_really_markdown(es1, NULL); 789 xs *bio1 = not_really_markdown(es1, NULL, NULL);
760 xs *tags = xs_list_new(); 790 xs *tags = xs_list_new();
761 xs *bio2 = process_tags(user, bio1, &tags); 791 xs *bio2 = process_tags(user, bio1, &tags);
762 792
@@ -774,7 +804,7 @@ static xs_html *html_user_body(snac *user, int read_only)
774 804
775 xs_dict *val_links = user->links; 805 xs_dict *val_links = user->links;
776 if (xs_is_null(val_links)) 806 if (xs_is_null(val_links))
777 val_links = xs_stock_dict; 807 val_links = xs_stock(XSTYPE_DICT);
778 808
779 xs_html *snac_metadata = xs_html_tag("div", 809 xs_html *snac_metadata = xs_html_tag("div",
780 xs_html_attr("class", "snac-metadata")); 810 xs_html_attr("class", "snac-metadata"));
@@ -852,9 +882,9 @@ xs_html *html_top_controls(snac *snac)
852 "new_post_div", "new_post_form", 882 "new_post_div", "new_post_form",
853 L("What's on your mind?"), "", 883 L("What's on your mind?"), "",
854 NULL, NULL, 884 NULL, NULL,
855 xs_stock_false, "", 885 xs_stock(XSTYPE_FALSE), "",
856 xs_stock_false, NULL, 886 xs_stock(XSTYPE_FALSE), NULL,
857 NULL, 1), 887 NULL, 1, "", ""),
858 888
859 /** operations **/ 889 /** operations **/
860 xs_html_tag("details", 890 xs_html_tag("details",
@@ -1219,6 +1249,11 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const
1219 xs_html_add(form, 1249 xs_html_add(form,
1220 html_button("like", L("Like"), L("Say you like this post"))); 1250 html_button("like", L("Like"), L("Say you like this post")));
1221 } 1251 }
1252 else {
1253 /* not like it anymore */
1254 xs_html_add(form,
1255 html_button("unlike", L("Unlike"), L("Nah don't like it that much")));
1256 }
1222 } 1257 }
1223 else { 1258 else {
1224 if (is_pinned(snac, id)) 1259 if (is_pinned(snac, id))
@@ -1235,6 +1270,11 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const
1235 xs_html_add(form, 1270 xs_html_add(form,
1236 html_button("boost", L("Boost"), L("Announce this post to your followers"))); 1271 html_button("boost", L("Boost"), L("Announce this post to your followers")));
1237 } 1272 }
1273 else {
1274 /* already boosted; add button to regret */
1275 xs_html_add(form,
1276 html_button("unboost", L("Unboost"), L("I regret I boosted this")));
1277 }
1238 } 1278 }
1239 1279
1240 if (strcmp(actor, snac->actor) != 0) { 1280 if (strcmp(actor, snac->actor) != 0) {
@@ -1278,6 +1318,20 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const
1278 xs *form_id = xs_fmt("%s_edit_form", md5); 1318 xs *form_id = xs_fmt("%s_edit_form", md5);
1279 xs *redir = xs_fmt("%s_entry", md5); 1319 xs *redir = xs_fmt("%s_entry", md5);
1280 1320
1321 char *att_file = "";
1322 char *att_alt_text = "";
1323 xs_list *att_list = xs_dict_get(msg, "attachment");
1324
1325 /* does it have an attachment? */
1326 if (xs_type(att_list) == XSTYPE_LIST && xs_list_len(att_list)) {
1327 xs_dict *d = xs_list_get(att_list, 0);
1328
1329 if (xs_type(d) == XSTYPE_DICT) {
1330 att_file = xs_dict_get_def(d, "url", "");
1331 att_alt_text = xs_dict_get_def(d, "name", "");
1332 }
1333 }
1334
1281 xs_html_add(controls, xs_html_tag("div", 1335 xs_html_add(controls, xs_html_tag("div",
1282 xs_html_tag("p", NULL), 1336 xs_html_tag("p", NULL),
1283 html_note(snac, L("Edit..."), 1337 html_note(snac, L("Edit..."),
@@ -1285,8 +1339,8 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const
1285 "", prev_src, 1339 "", prev_src,
1286 id, NULL, 1340 id, NULL,
1287 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), 1341 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"),
1288 xs_stock_false, redir, 1342 xs_stock(XSTYPE_FALSE), redir,
1289 NULL, 0)), 1343 NULL, 0, att_file, att_alt_text)),
1290 xs_html_tag("p", NULL)); 1344 xs_html_tag("p", NULL));
1291 } 1345 }
1292 1346
@@ -1304,8 +1358,8 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const
1304 "", ct, 1358 "", ct,
1305 NULL, NULL, 1359 NULL, NULL,
1306 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), 1360 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"),
1307 xs_stock_false, redir, 1361 xs_stock(XSTYPE_FALSE), redir,
1308 id, 0)), 1362 id, 0, "", "")),
1309 xs_html_tag("p", NULL)); 1363 xs_html_tag("p", NULL));
1310 } 1364 }
1311 1365
@@ -1858,6 +1912,9 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
1858 1912
1859 xs_list *p = children; 1913 xs_list *p = children;
1860 char *cmd5; 1914 char *cmd5;
1915 int cnt = 0;
1916 int o_cnt = 0;
1917
1861 while (xs_list_iter(&p, &cmd5)) { 1918 while (xs_list_iter(&p, &cmd5)) {
1862 xs *chd = NULL; 1919 xs *chd = NULL;
1863 1920
@@ -1866,23 +1923,40 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
1866 else 1923 else
1867 object_get_by_md5(cmd5, &chd); 1924 object_get_by_md5(cmd5, &chd);
1868 1925
1869 if (chd != NULL && xs_is_null(xs_dict_get(chd, "name"))) { 1926 if (chd != NULL) {
1870 xs_html *che = html_entry(user, chd, read_only, level + 1, cmd5, hide_children); 1927 if (xs_is_null(xs_dict_get(chd, "name"))) {
1928 xs_html *che = html_entry(user, chd, read_only,
1929 level + 1, cmd5, hide_children);
1930
1931 if (che != NULL) {
1932 if (left > 3) {
1933 xs_html_add(ch_older,
1934 che);
1935
1936 o_cnt++;
1937 }
1938 else
1939 xs_html_add(ch_container,
1940 che);
1871 1941
1872 if (che != NULL) { 1942 cnt++;
1873 if (left > 3) 1943 }
1874 xs_html_add(ch_older,
1875 che);
1876 else
1877 xs_html_add(ch_container,
1878 che);
1879 } 1944 }
1945
1946 left--;
1880 } 1947 }
1881 else 1948 else
1882 srv_debug(2, xs_fmt("cannot read child %s", cmd5)); 1949 srv_debug(2, xs_fmt("cannot read child %s", cmd5));
1883
1884 left--;
1885 } 1950 }
1951
1952 /* if no children were finally added, hide the details */
1953 if (cnt == 0)
1954 xs_html_add(ch_details,
1955 xs_html_attr("style", "display: none"));
1956
1957 if (o_cnt == 0 && ch_older)
1958 xs_html_add(ch_older,
1959 xs_html_attr("style", "display: none"));
1886 } 1960 }
1887 } 1961 }
1888 1962
@@ -1917,6 +1991,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
1917 double t = ftime(); 1991 double t = ftime();
1918 1992
1919 xs *desc = NULL; 1993 xs *desc = NULL;
1994 xs *alternate = NULL;
1920 1995
1921 if (xs_list_len(list) == 1) { 1996 if (xs_list_len(list) == 1) {
1922 /* only one element? pick the description from the source */ 1997 /* only one element? pick the description from the source */
@@ -1925,13 +2000,15 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
1925 object_get_by_md5(id, &d); 2000 object_get_by_md5(id, &d);
1926 if (d && (v = xs_dict_get(d, "sourceContent")) != NULL) 2001 if (d && (v = xs_dict_get(d, "sourceContent")) != NULL)
1927 desc = xs_dup(v); 2002 desc = xs_dup(v);
2003
2004 alternate = xs_dup(xs_dict_get(d, "id"));
1928 } 2005 }
1929 2006
1930 xs_html *head; 2007 xs_html *head;
1931 xs_html *body; 2008 xs_html *body;
1932 2009
1933 if (user) { 2010 if (user) {
1934 head = html_user_head(user, desc); 2011 head = html_user_head(user, desc, alternate);
1935 body = html_user_body(user, read_only); 2012 body = html_user_body(user, read_only);
1936 } 2013 }
1937 else { 2014 else {
@@ -1977,9 +2054,16 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
1977 if (user != NULL && !is_msg_public(msg)) { 2054 if (user != NULL && !is_msg_public(msg)) {
1978 char *irt = xs_dict_get(msg, "inReplyTo"); 2055 char *irt = xs_dict_get(msg, "inReplyTo");
1979 2056
2057 /* is it a reply to something not in the storage? */
1980 if (!xs_is_null(irt) && !object_here(irt)) { 2058 if (!xs_is_null(irt) && !object_here(irt)) {
1981 snac_debug(user, 1, xs_fmt("skipping non-public reply to an unknown post %s", v)); 2059 /* is it for me? */
1982 continue; 2060 xs_list *to = xs_dict_get_def(msg, "to", xs_stock(XSTYPE_LIST));
2061 xs_list *cc = xs_dict_get_def(msg, "cc", xs_stock(XSTYPE_LIST));
2062
2063 if (xs_list_in(to, user->actor) == -1 && xs_list_in(cc, user->actor) == -1) {
2064 snac_debug(user, 1, xs_fmt("skipping non-public reply to an unknown post %s", v));
2065 continue;
2066 }
1983 } 2067 }
1984 } 2068 }
1985 2069
@@ -2077,9 +2161,7 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t)
2077 snac_posts = xs_html_tag("details", 2161 snac_posts = xs_html_tag("details",
2078 xs_html_attr("open", NULL), 2162 xs_html_attr("open", NULL),
2079 xs_html_tag("summary", 2163 xs_html_tag("summary",
2080 xs_html_text("...")), 2164 xs_html_text("..."))));
2081 xs_html_tag("div",
2082 xs_html_attr("class", "snac-posts"))));
2083 2165
2084 xs_list *p = list; 2166 xs_list *p = list;
2085 char *actor_id; 2167 char *actor_id;
@@ -2181,9 +2263,9 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t)
2181 dm_div_id, dm_form_id, 2263 dm_div_id, dm_form_id,
2182 "", "", 2264 "", "",
2183 NULL, actor_id, 2265 NULL, actor_id,
2184 xs_stock_false, "", 2266 xs_stock(XSTYPE_FALSE), "",
2185 xs_stock_false, NULL, 2267 xs_stock(XSTYPE_FALSE), NULL,
2186 NULL, 0), 2268 NULL, 0, "", ""),
2187 xs_html_tag("p", NULL)); 2269 xs_html_tag("p", NULL));
2188 2270
2189 xs_html_add(snac_post, snac_controls); 2271 xs_html_add(snac_post, snac_controls);
@@ -2202,10 +2284,12 @@ xs_str *html_people(snac *user)
2202 xs *wers = follower_list(user); 2284 xs *wers = follower_list(user);
2203 2285
2204 xs_html *html = xs_html_tag("html", 2286 xs_html *html = xs_html_tag("html",
2205 html_user_head(user, NULL), 2287 html_user_head(user, NULL, NULL),
2206 xs_html_add(html_user_body(user, 0), 2288 xs_html_add(html_user_body(user, 0),
2207 html_people_list(user, wing, L("People you follow"), "i"), 2289 xs_html_tag("div",
2208 html_people_list(user, wers, L("People that follow you"), "e"), 2290 xs_html_attr("class", "snac-posts"),
2291 html_people_list(user, wing, L("People you follow"), "i"),
2292 html_people_list(user, wers, L("People that follow you"), "e")),
2209 html_footer())); 2293 html_footer()));
2210 2294
2211 return xs_html_render_s(html, "<!DOCTYPE html>\n"); 2295 return xs_html_render_s(html, "<!DOCTYPE html>\n");
@@ -2220,7 +2304,7 @@ xs_str *html_notifications(snac *user, int skip, int show)
2220 xs_html *body = html_user_body(user, 0); 2304 xs_html *body = html_user_body(user, 0);
2221 2305
2222 xs_html *html = xs_html_tag("html", 2306 xs_html *html = xs_html_tag("html",
2223 html_user_head(user, NULL), 2307 html_user_head(user, NULL, NULL),
2224 body); 2308 body);
2225 2309
2226 xs *clear_all_action = xs_fmt("%s/admin/clear-notifications", user->actor); 2310 xs *clear_all_action = xs_fmt("%s/admin/clear-notifications", user->actor);
@@ -2604,7 +2688,7 @@ int html_get_handler(const xs_dict *req, const char *q_path,
2604 return 403; 2688 return 403;
2605 2689
2606 xs *elems = timeline_simple_list(&snac, "public", 0, 20); 2690 xs *elems = timeline_simple_list(&snac, "public", 0, 20);
2607 xs *bio = not_really_markdown(xs_dict_get(snac.config, "bio"), NULL); 2691 xs *bio = not_really_markdown(xs_dict_get(snac.config, "bio"), NULL, NULL);
2608 2692
2609 xs *rss_title = xs_fmt("%s (@%s@%s)", 2693 xs *rss_title = xs_fmt("%s (@%s@%s)",
2610 xs_dict_get(snac.config, "name"), 2694 xs_dict_get(snac.config, "name"),
@@ -2802,7 +2886,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
2802 msg = msg_note(&snac, content_2, to, in_reply_to, attach_list, priv); 2886 msg = msg_note(&snac, content_2, to, in_reply_to, attach_list, priv);
2803 2887
2804 if (sensitive != NULL) { 2888 if (sensitive != NULL) {
2805 msg = xs_dict_set(msg, "sensitive", xs_stock_true); 2889 msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE));
2806 msg = xs_dict_set(msg, "summary", xs_is_null(summary) ? "..." : summary); 2890 msg = xs_dict_set(msg, "summary", xs_is_null(summary) ? "..." : summary);
2807 } 2891 }
2808 2892
@@ -2881,6 +2965,22 @@ int html_post_handler(const xs_dict *req, const char *q_path,
2881 } 2965 }
2882 } 2966 }
2883 else 2967 else
2968 if (strcmp(action, L("Unlike")) == 0) { /** **/
2969 xs *msg = msg_repulsion(&snac, id, "Like");
2970
2971 if (msg != NULL) {
2972 enqueue_message(&snac, msg);
2973 }
2974 }
2975 else
2976 if (strcmp(action, L("Unboost")) == 0) { /** **/
2977 xs *msg = msg_repulsion(&snac, id, "Announce");
2978
2979 if (msg != NULL) {
2980 enqueue_message(&snac, msg);
2981 }
2982 }
2983 else
2884 if (strcmp(action, L("MUTE")) == 0) { /** **/ 2984 if (strcmp(action, L("MUTE")) == 0) { /** **/
2885 mute(&snac, actor); 2985 mute(&snac, actor);
2886 } 2986 }
@@ -3036,17 +3136,17 @@ int html_post_handler(const xs_dict *req, const char *q_path,
3036 snac.config = xs_dict_set(snac.config, "purge_days", days); 3136 snac.config = xs_dict_set(snac.config, "purge_days", days);
3037 } 3137 }
3038 if ((v = xs_dict_get(p_vars, "drop_dm_from_unknown")) != NULL && strcmp(v, "on") == 0) 3138 if ((v = xs_dict_get(p_vars, "drop_dm_from_unknown")) != NULL && strcmp(v, "on") == 0)
3039 snac.config = xs_dict_set(snac.config, "drop_dm_from_unknown", xs_stock_true); 3139 snac.config = xs_dict_set(snac.config, "drop_dm_from_unknown", xs_stock(XSTYPE_TRUE));
3040 else 3140 else
3041 snac.config = xs_dict_set(snac.config, "drop_dm_from_unknown", xs_stock_false); 3141 snac.config = xs_dict_set(snac.config, "drop_dm_from_unknown", xs_stock(XSTYPE_FALSE));
3042 if ((v = xs_dict_get(p_vars, "bot")) != NULL && strcmp(v, "on") == 0) 3142 if ((v = xs_dict_get(p_vars, "bot")) != NULL && strcmp(v, "on") == 0)
3043 snac.config = xs_dict_set(snac.config, "bot", xs_stock_true); 3143 snac.config = xs_dict_set(snac.config, "bot", xs_stock(XSTYPE_TRUE));
3044 else 3144 else
3045 snac.config = xs_dict_set(snac.config, "bot", xs_stock_false); 3145 snac.config = xs_dict_set(snac.config, "bot", xs_stock(XSTYPE_FALSE));
3046 if ((v = xs_dict_get(p_vars, "private")) != NULL && strcmp(v, "on") == 0) 3146 if ((v = xs_dict_get(p_vars, "private")) != NULL && strcmp(v, "on") == 0)
3047 snac.config = xs_dict_set(snac.config, "private", xs_stock_true); 3147 snac.config = xs_dict_set(snac.config, "private", xs_stock(XSTYPE_TRUE));
3048 else 3148 else
3049 snac.config = xs_dict_set(snac.config, "private", xs_stock_false); 3149 snac.config = xs_dict_set(snac.config, "private", xs_stock(XSTYPE_FALSE));
3050 if ((v = xs_dict_get(p_vars, "metadata")) != NULL) { 3150 if ((v = xs_dict_get(p_vars, "metadata")) != NULL) {
3051 /* split the metadata and store it as a dict */ 3151 /* split the metadata and store it as a dict */
3052 xs_dict *md = xs_dict_new(); 3152 xs_dict *md = xs_dict_new();