summaryrefslogtreecommitdiff
path: root/html.c
diff options
context:
space:
mode:
authorGravatar grunfink2025-09-28 15:46:56 +0200
committerGravatar grunfink2025-09-28 15:46:56 +0200
commitab698c2bd6cbe74b2cca0a17fe210e159a43a2ce (patch)
tree868fa6b77c7697f972cb7b9ea8d3ff49ab8652e1 /html.c
parentTemporary tweak. (diff)
parentMerge branch 'master' into feature/visibility (diff)
downloadpenes-snac2-ab698c2bd6cbe74b2cca0a17fe210e159a43a2ce.tar.gz
penes-snac2-ab698c2bd6cbe74b2cca0a17fe210e159a43a2ce.tar.xz
penes-snac2-ab698c2bd6cbe74b2cca0a17fe210e159a43a2ce.zip
Merge pull request 'implementing scopes' (#474) from byte/snac2:feature/visibility into master
Reviewed-on: https://codeberg.org/grunfink/snac2/pulls/474
Diffstat (limited to 'html.c')
-rw-r--r--html.c144
1 files changed, 112 insertions, 32 deletions
diff --git a/html.c b/html.c
index ed9e739..2fca837 100644
--- a/html.c
+++ b/html.c
@@ -165,7 +165,7 @@ xs_str *format_text_with_emoji(snac *user, const char *text, int ems, const char
165 165
166 166
167xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, 167xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date,
168 const char *udate, const char *url, int priv, 168 const char *udate, const char *url, int scope,
169 int in_people, const char *proxy, const char *lang, 169 int in_people, const char *proxy, const char *lang,
170 const char *md5) 170 const char *md5)
171{ 171{
@@ -249,12 +249,35 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date,
249 xs_html_raw("🤝"))); 249 xs_html_raw("🤝")));
250 } 250 }
251 251
252 if (priv) { 252 if (scope != -1) {
253 xs_html_add(actor_icon, 253 if (scope == SCOPE_FOLLOWERS) {
254 xs_html_text(" "), 254 xs_html_add(actor_icon,
255 xs_html_tag("span", 255 xs_html_text(" "),
256 xs_html_attr("title", "private"), 256 xs_html_tag("span",
257 xs_html_raw("🔒"))); 257 xs_html_attr("title", "followers"),
258 xs_html_raw("🔒"))); // emoji of a lock
259 }
260 else if (scope == SCOPE_PUBLIC) {
261 xs_html_add(actor_icon,
262 xs_html_text(" "),
263 xs_html_tag("span",
264 xs_html_attr("title", "public"),
265 xs_html_raw("🌐"))); // emoji of a globe
266 }
267 else if (scope == SCOPE_UNLISTED) {
268 xs_html_add(actor_icon,
269 xs_html_text(" "),
270 xs_html_tag("span",
271 xs_html_attr("title", "unlisted"),
272 xs_html_raw("🔓"))); // emoji of an unlocked lock
273 }
274 else if (scope == SCOPE_MENTIONED) {
275 xs_html_add(actor_icon,
276 xs_html_text(" "),
277 xs_html_tag("span",
278 xs_html_attr("title", "mentioned"),
279 xs_html_raw("✉️"))); // emoji of a mail
280 }
258 } 281 }
259 282
260 if (xs_is_null(date)) { 283 if (xs_is_null(date)) {
@@ -342,18 +365,17 @@ xs_html *html_msg_icon(snac *user, const char *actor_id, const xs_dict *msg,
342 const char *date = NULL; 365 const char *date = NULL;
343 const char *udate = NULL; 366 const char *udate = NULL;
344 const char *url = NULL; 367 const char *url = NULL;
345 int priv = 0;
346 const char *type = xs_dict_get(msg, "type"); 368 const char *type = xs_dict_get(msg, "type");
369 const int scope = get_msg_visibility(msg);
347 370
348 if (xs_match(type, POSTLIKE_OBJECT_TYPE)) 371 if (xs_match(type, POSTLIKE_OBJECT_TYPE))
349 url = xs_dict_get(msg, "id"); 372 url = xs_dict_get(msg, "id");
350 373
351 priv = !is_msg_public(msg);
352 374
353 date = xs_dict_get(msg, "published"); 375 date = xs_dict_get(msg, "published");
354 udate = xs_dict_get(msg, "updated"); 376 udate = xs_dict_get(msg, "updated");
355 377
356 actor_icon = html_actor_icon(user, actor, date, udate, url, priv, 0, proxy, lang, md5); 378 actor_icon = html_actor_icon(user, actor, date, udate, url, scope, 0, proxy, lang, md5);
357 } 379 }
358 380
359 return actor_icon; 381 return actor_icon;
@@ -365,7 +387,7 @@ xs_html *html_note(snac *user, const char *summary,
365 const char *ta_plh, const char *ta_content, 387 const char *ta_plh, const char *ta_content,
366 const char *edit_id, const char *actor_id, 388 const char *edit_id, const char *actor_id,
367 const xs_val *cw_yn, const char *cw_text, 389 const xs_val *cw_yn, const char *cw_text,
368 const xs_val *mnt_only, const char *redir, 390 const int scope, const char *redir,
369 const char *in_reply_to, int poll, 391 const char *in_reply_to, int poll,
370 const xs_list *att_files, const xs_list *att_alt_texts, 392 const xs_list *att_files, const xs_list *att_alt_texts,
371 int is_draft, const char *published, 393 int is_draft, const char *published,
@@ -417,14 +439,44 @@ xs_html *html_note(snac *user, const char *summary,
417 xs_html_attr("name", "to"), 439 xs_html_attr("name", "to"),
418 xs_html_attr("value", actor_id))); 440 xs_html_attr("value", actor_id)));
419 else { 441 else {
420 /* no actor_id; ask for mentioned_only */
421 xs_html_add(form, 442 xs_html_add(form,
422 xs_html_tag("p", NULL), 443 xs_html_tag("p",
423 xs_html_text(L("Only for mentioned people: ")), 444 xs_html_text(L("Visibility: ")),
424 xs_html_sctag("input", 445 xs_html_tag("label",
425 xs_html_attr("type", "checkbox"), 446 xs_html_sctag("input",
426 xs_html_attr("name", "mentioned_only"), 447 xs_html_attr("type", "radio"),
427 xs_html_attr(xs_type(mnt_only) == XSTYPE_TRUE ? "checked" : "", NULL))); 448 xs_html_attr("name", "visibility"),
449 xs_html_attr("value", "public"),
450 xs_html_attr(scope == SCOPE_PUBLIC ? "checked" : "", NULL)),
451 xs_html_text(" "),
452 xs_html_text(L("Public"))),
453 xs_html_text(" "),
454 xs_html_tag("label",
455 xs_html_sctag("input",
456 xs_html_attr("type", "radio"),
457 xs_html_attr("name", "visibility"),
458 xs_html_attr("value", "unlisted"),
459 xs_html_attr(scope == SCOPE_UNLISTED ? "checked" : "", NULL)),
460 xs_html_text(" "),
461 xs_html_text(L("Unlisted"))),
462 xs_html_text(" "),
463 xs_html_tag("label",
464 xs_html_sctag("input",
465 xs_html_attr("type", "radio"),
466 xs_html_attr("name", "visibility"),
467 xs_html_attr("value", "followers"),
468 xs_html_attr(scope == SCOPE_FOLLOWERS ? "checked" : "", NULL)),
469 xs_html_text(" "),
470 xs_html_text(L("Followers-only"))),
471 xs_html_text(" "),
472 xs_html_tag("label",
473 xs_html_sctag("input",
474 xs_html_attr("type", "radio"),
475 xs_html_attr("name", "visibility"),
476 xs_html_attr("value", "mentioned"),
477 xs_html_attr(scope == SCOPE_MENTIONED ? "checked" : "", NULL)),
478 xs_html_text(" "),
479 xs_html_text(L("Direct Message")))));
428 } 480 }
429 481
430 if (redir) 482 if (redir)
@@ -1236,7 +1288,7 @@ xs_html *html_top_controls(snac *user)
1236 L("What's on your mind?"), "", 1288 L("What's on your mind?"), "",
1237 NULL, NULL, 1289 NULL, NULL,
1238 xs_stock(XSTYPE_FALSE), "", 1290 xs_stock(XSTYPE_FALSE), "",
1239 xs_stock(XSTYPE_FALSE), NULL, 1291 SCOPE_PUBLIC, NULL,
1240 NULL, 1, NULL, NULL, 0, NULL, NULL), 1292 NULL, 1, NULL, NULL, 0, NULL, NULL),
1241 1293
1242 /** operations **/ 1294 /** operations **/
@@ -1942,6 +1994,8 @@ xs_html *html_entry_controls(snac *user, const char *actor,
1942 xs_dict_next(cmap, &note_lang, &dummy, &c); 1994 xs_dict_next(cmap, &note_lang, &dummy, &c);
1943 } 1995 }
1944 1996
1997 const int edit_scope = get_msg_visibility(msg);
1998
1945 xs_html_add(controls, xs_html_tag("div", 1999 xs_html_add(controls, xs_html_tag("div",
1946 xs_html_tag("p", NULL), 2000 xs_html_tag("p", NULL),
1947 html_note(user, L("Edit..."), 2001 html_note(user, L("Edit..."),
@@ -1949,7 +2003,7 @@ xs_html *html_entry_controls(snac *user, const char *actor,
1949 "", prev_src, 2003 "", prev_src,
1950 id, NULL, 2004 id, NULL,
1951 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), 2005 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"),
1952 xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir, 2006 edit_scope, redir,
1953 NULL, 0, att_files, att_alt_texts, is_draft(user, id), 2007 NULL, 0, att_files, att_alt_texts, is_draft(user, id),
1954 xs_dict_get(msg, "published"), note_lang)), 2008 xs_dict_get(msg, "published"), note_lang)),
1955 xs_html_tag("p", NULL)); 2009 xs_html_tag("p", NULL));
@@ -1962,6 +2016,8 @@ xs_html *html_entry_controls(snac *user, const char *actor,
1962 xs *form_id = xs_fmt("%s_reply_form", md5); 2016 xs *form_id = xs_fmt("%s_reply_form", md5);
1963 xs *redir = xs_fmt("%s_entry", md5); 2017 xs *redir = xs_fmt("%s_entry", md5);
1964 2018
2019 const int scope = get_msg_visibility(msg);
2020
1965 xs_html_add(controls, xs_html_tag("div", 2021 xs_html_add(controls, xs_html_tag("div",
1966 xs_html_tag("p", NULL), 2022 xs_html_tag("p", NULL),
1967 html_note(user, L("Reply..."), 2023 html_note(user, L("Reply..."),
@@ -1969,7 +2025,7 @@ xs_html *html_entry_controls(snac *user, const char *actor,
1969 "", ct, 2025 "", ct,
1970 NULL, NULL, 2026 NULL, NULL,
1971 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), 2027 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"),
1972 xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir, 2028 scope, redir,
1973 id, 0, NULL, NULL, 0, NULL, NULL)), 2029 id, 0, NULL, NULL, 0, NULL, NULL)),
1974 xs_html_tag("p", NULL)); 2030 xs_html_tag("p", NULL));
1975 } 2031 }
@@ -2061,6 +2117,12 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
2061 xs_html_attr("name", s1))); 2117 xs_html_attr("name", s1)));
2062 } 2118 }
2063 2119
2120 /* don't show followers-only notes from not followed users */
2121 if (user && get_msg_visibility(msg) == SCOPE_FOLLOWERS &&
2122 strcmp(user->actor, actor) != 0 && following_check(user, actor) == 0) {
2123 return NULL;
2124 }
2125
2064 if ((user == NULL || strcmp(actor, user->actor) != 0) 2126 if ((user == NULL || strcmp(actor, user->actor) != 0)
2065 && !valid_status(actor_get(actor, NULL))) { 2127 && !valid_status(actor_get(actor, NULL))) {
2066 2128
@@ -2275,7 +2337,6 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
2275 2337
2276 has_title = 1; 2338 has_title = 1;
2277 } 2339 }
2278
2279 snac_content = xs_html_tag("div", NULL); 2340 snac_content = xs_html_tag("div", NULL);
2280 } 2341 }
2281 2342
@@ -3089,8 +3150,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
3089 xs_html_text(title))); 3150 xs_html_text(title)));
3090 } 3151 }
3091 3152
3092 xs_html_add(body, 3153 xs_html_add(body, posts);
3093 posts);
3094 3154
3095 int mark_shown = 0; 3155 int mark_shown = 0;
3096 3156
@@ -3130,8 +3190,9 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
3130 if (user == NULL && is_msg_from_private_user(msg)) 3190 if (user == NULL && is_msg_from_private_user(msg))
3131 continue; 3191 continue;
3132 3192
3133 /* is this message a non-public reply? */ 3193 const int scope = get_msg_visibility(msg);
3134 if (user != NULL && !is_msg_public(msg)) { 3194 if (user != NULL && scope != SCOPE_PUBLIC){
3195 /* is this message a non-public reply? */
3135 const char *irt = get_in_reply_to(msg); 3196 const char *irt = get_in_reply_to(msg);
3136 3197
3137 /* is it a reply to something not in the storage? */ 3198 /* is it a reply to something not in the storage? */
@@ -3146,6 +3207,14 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
3146 } 3207 }
3147 } 3208 }
3148 } 3209 }
3210 /* hide non-public posts from /instance view */
3211 if (page != NULL && strcmp(page, "/instance") == 0 && scope != SCOPE_PUBLIC){
3212 continue;
3213 }
3214 /* hide non-public posts viewed from outside */
3215 if (read_only && scope != SCOPE_PUBLIC){
3216 continue;
3217 }
3149 3218
3150 xs_html *entry = html_entry(user, msg, read_only, 0, v, (user && !hide_children) ? 0 : 1); 3219 xs_html *entry = html_entry(user, msg, read_only, 0, v, (user && !hide_children) ? 0 : 1);
3151 3220
@@ -3256,7 +3325,7 @@ xs_html *html_people_list(snac *user, xs_list *list, const char *header, const c
3256 xs_html_tag("div", 3325 xs_html_tag("div",
3257 xs_html_attr("class", "snac-post-header"), 3326 xs_html_attr("class", "snac-post-header"),
3258 html_actor_icon(user, actor, xs_dict_get(actor, "published"), 3327 html_actor_icon(user, actor, xs_dict_get(actor, "published"),
3259 NULL, NULL, 0, 1, proxy, NULL, NULL))); 3328 NULL, NULL, -1, 1, proxy, NULL, NULL)));
3260 3329
3261 /* content (user bio) */ 3330 /* content (user bio) */
3262 const char *c = xs_dict_get(actor, "summary"); 3331 const char *c = xs_dict_get(actor, "summary");
@@ -3357,7 +3426,7 @@ xs_html *html_people_list(snac *user, xs_list *list, const char *header, const c
3357 "", "", 3426 "", "",
3358 NULL, actor_id, 3427 NULL, actor_id,
3359 xs_stock(XSTYPE_FALSE), "", 3428 xs_stock(XSTYPE_FALSE), "",
3360 xs_stock(XSTYPE_FALSE), NULL, 3429 SCOPE_MENTIONED, NULL,
3361 NULL, 0, NULL, NULL, 0, NULL, NULL), 3430 NULL, 0, NULL, NULL, 0, NULL, NULL),
3362 xs_html_tag("p", NULL)); 3431 xs_html_tag("p", NULL));
3363 3432
@@ -3564,7 +3633,7 @@ xs_str *html_notifications(snac *user, int skip, int show)
3564 xs_html_add(entry, 3633 xs_html_add(entry,
3565 xs_html_tag("div", 3634 xs_html_tag("div",
3566 xs_html_attr("class", "snac-post"), 3635 xs_html_attr("class", "snac-post"),
3567 html_actor_icon(user, actor, NULL, NULL, NULL, 0, 0, proxy, NULL, NULL))); 3636 html_actor_icon(user, actor, NULL, NULL, NULL, -1, 0, proxy, NULL, NULL)));
3568 } 3637 }
3569 else 3638 else
3570 if (strcmp(type, "Move") == 0) { 3639 if (strcmp(type, "Move") == 0) {
@@ -3578,7 +3647,7 @@ xs_str *html_notifications(snac *user, int skip, int show)
3578 xs_html_add(entry, 3647 xs_html_add(entry,
3579 xs_html_tag("div", 3648 xs_html_tag("div",
3580 xs_html_attr("class", "snac-post"), 3649 xs_html_attr("class", "snac-post"),
3581 html_actor_icon(user, old_actor, NULL, NULL, NULL, 0, 0, proxy, NULL, NULL))); 3650 html_actor_icon(user, old_actor, NULL, NULL, NULL, -1, 0, proxy, NULL, NULL)));
3582 } 3651 }
3583 } 3652 }
3584 } 3653 }
@@ -4445,7 +4514,18 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4445 const char *post_date = xs_dict_get_def(p_vars, "post_date", ""); 4514 const char *post_date = xs_dict_get_def(p_vars, "post_date", "");
4446 const char *post_time = xs_dict_get_def(p_vars, "post_time", ""); 4515 const char *post_time = xs_dict_get_def(p_vars, "post_time", "");
4447 const char *post_lang = xs_dict_get(p_vars, "post_lang"); 4516 const char *post_lang = xs_dict_get(p_vars, "post_lang");
4448 int priv = !xs_is_null(xs_dict_get(p_vars, "mentioned_only")); 4517 const char *visibility = xs_dict_get(p_vars, "visibility");
4518 int scope = SCOPE_PUBLIC; /* default to public */
4519 if (!xs_is_null(visibility)) {
4520 if (strcmp(visibility, "unlisted") == 0)
4521 scope = SCOPE_UNLISTED;
4522 else
4523 if (strcmp(visibility, "followers") == 0)
4524 scope = SCOPE_FOLLOWERS;
4525 else
4526 if (strcmp(visibility, "mentioned") == 0)
4527 scope = SCOPE_MENTIONED;
4528 }
4449 int store_as_draft = !xs_is_null(xs_dict_get(p_vars, "is_draft")); 4529 int store_as_draft = !xs_is_null(xs_dict_get(p_vars, "is_draft"));
4450 xs *attach_list = xs_list_new(); 4530 xs *attach_list = xs_list_new();
4451 4531
@@ -4528,7 +4608,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4528 enqueue_close_question(&snac, xs_dict_get(msg, "id"), end_secs); 4608 enqueue_close_question(&snac, xs_dict_get(msg, "id"), end_secs);
4529 } 4609 }
4530 else 4610 else
4531 msg = msg_note(&snac, content_2, to, in_reply_to, attach_list, priv, post_lang, NULL); 4611 msg = msg_note(&snac, content_2, to, in_reply_to, attach_list, scope, post_lang, NULL);
4532 4612
4533 if (sensitive != NULL) { 4613 if (sensitive != NULL) {
4534 msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE)); 4614 msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE));