summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar byte2026-01-18 22:13:21 +0000
committerGravatar byte2026-01-25 16:56:04 +0100
commit56ca23c68c76fc1225f64b3d19e7c23954b2e8a3 (patch)
treea538ad4637be429a95462a30b2e4e05069f86d9c
parentBumped version. (diff)
downloadsnac2-56ca23c68c76fc1225f64b3d19e7c23954b2e8a3.tar.gz
snac2-56ca23c68c76fc1225f64b3d19e7c23954b2e8a3.tar.xz
snac2-56ca23c68c76fc1225f64b3d19e7c23954b2e8a3.zip
notifications filter
-rw-r--r--data.c66
-rw-r--r--html.c211
-rw-r--r--snac.h1
3 files changed, 198 insertions, 80 deletions
diff --git a/data.c b/data.c
index f01ae92..27825ad 100644
--- a/data.c
+++ b/data.c
@@ -3503,11 +3503,75 @@ xs_list *notify_list(snac *snac, int skip, int show)
3503} 3503}
3504 3504
3505 3505
3506xs_list *notify_filter_list(snac *snac, xs_list *notifs)
3507/* apply user-defined notification filter to IDs */
3508{
3509 const xs_dict *n_filter = xs_dict_get(snac->config, "notify_filter");
3510 if (!n_filter) {
3511 return xs_dup(notifs);
3512 }
3513 const xs_val *n_def = xs_stock( XSTYPE_TRUE );
3514 int n_likes_on = xs_is_true(xs_dict_get_def(n_filter, "likes", n_def));
3515 int n_reacts_on = xs_is_true(xs_dict_get_def(n_filter, "reacts", n_def));
3516 int n_ments_on = xs_is_true(xs_dict_get_def(n_filter, "mentions", n_def));
3517 int n_ann_on = xs_is_true(xs_dict_get_def(n_filter, "announces", n_def));
3518 int n_fol_on = xs_is_true(xs_dict_get_def(n_filter, "follows", n_def));
3519 int n_unfol_on = xs_is_true(xs_dict_get_def(n_filter, "unfollows", n_def));
3520 int n_folreq_on = xs_is_true(xs_dict_get_def(n_filter, "folreqs", n_def));
3521 int n_blocks_on = xs_is_true(xs_dict_get_def(n_filter, "blocks", n_def));
3522 int n_polls_on = xs_is_true(xs_dict_get_def(n_filter, "polls", n_def));
3523
3524 const xs_str *v;
3525 xs_list *flt = xs_list_new();
3526
3527 xs_list_foreach(notifs, v) {
3528 xs *noti = notify_get(snac, v);
3529
3530 if (noti == NULL)
3531 continue;
3532
3533 const char *type = xs_dict_get(noti, "type");
3534 const char *utype = xs_dict_get(noti, "utype");
3535 const char *actor_id = xs_dict_get(noti, "actor");
3536 if (strcmp(type, "EmojiReact") == 0 && xs_is_true(xs_dict_get(srv_config, "disable_emojireact")))
3537 continue;
3538 if (strcmp(type, "Create") == 0 && !n_ments_on)
3539 continue;
3540 if (strcmp(type, "Update") == 0 && strcmp(utype, "Question") == 0 && !n_polls_on)
3541 continue;
3542 if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0 && !n_unfol_on)
3543 continue;
3544 if (strcmp(type, "EmojiReact") == 0 || strcmp(type, "Like") == 0) {
3545 if (strcmp(type, "Like") == 0 && !n_likes_on)
3546 continue;
3547 if (strcmp(type, "EmojiReact") == 0 && !n_reacts_on)
3548 continue;
3549 }
3550 if (strcmp(type, "Follow") == 0) {
3551 if (pending_check(snac, actor_id)) {
3552 if (!n_folreq_on)
3553 continue;
3554 }
3555 else
3556 if (!n_fol_on)
3557 continue;
3558 }
3559 if (strcmp(type, "Block") == 0 && !n_blocks_on)
3560 continue;
3561 if (strcmp(type, "Announce") == 0 && !n_ann_on)
3562 continue;
3563 flt = xs_list_append(flt, v);
3564 }
3565 return flt;
3566}
3567
3568
3506int notify_new_num(snac *snac) 3569int notify_new_num(snac *snac)
3507/* counts the number of new notifications */ 3570/* counts the number of new notifications */
3508{ 3571{
3509 xs *t = notify_check_time(snac, 0); 3572 xs *t = notify_check_time(snac, 0);
3510 xs *lst = notify_list(snac, 0, XS_ALL); 3573 xs *lst_unfilt = notify_list(snac, 0, XS_ALL);
3574 xs *lst = notify_filter_list(snac, lst_unfilt);
3511 int cnt = 0; 3575 int cnt = 0;
3512 3576
3513 xs_list *p = lst; 3577 xs_list *p = lst;
diff --git a/html.c b/html.c
index 66ce738..c862195 100644
--- a/html.c
+++ b/html.c
@@ -492,7 +492,7 @@ void html_note_render_visibility(snac* user, xs_html *form, const int scope)
492 492
493 xs_html *paragraph = xs_html_tag("p", xs_html_text(L("Visibility: "))); 493 xs_html *paragraph = xs_html_tag("p", xs_html_text(L("Visibility: ")));
494 const int* to_render = scopes[scope]; 494 const int* to_render = scopes[scope];
495 for( int i = 0; to_render[i] != -1; i++ ){ 495 for( int i = 0; to_render[i] != -1; i++ ) {
496 const int scope_i = to_render[i]; 496 const int scope_i = to_render[i];
497 const char* value = scopes_tags[scope_i]; 497 const char* value = scopes_tags[scope_i];
498 const char* name = scopes_names[scope_i]; 498 const char* name = scopes_names[scope_i];
@@ -1422,6 +1422,20 @@ static xs_html *html_user_body(snac *user, int read_only)
1422} 1422}
1423 1423
1424 1424
1425xs_html *html_checkbox(const char *form_name, const char *label, int flag)
1426/* helper for checkbox rendering */
1427{
1428 return xs_html_tag("p",
1429 xs_html_sctag("input",
1430 xs_html_attr("type", "checkbox"),
1431 xs_html_attr("name", form_name),
1432 xs_html_attr(flag ? "checked" : "", NULL)),
1433 xs_html_tag("label",
1434 xs_html_attr("for", form_name),
1435 xs_html_text(label)));
1436}
1437
1438
1425xs_html *html_top_controls(snac *user) 1439xs_html *html_top_controls(snac *user)
1426/* generates the top controls */ 1440/* generates the top controls */
1427{ 1441{
@@ -1745,70 +1759,21 @@ xs_html *html_top_controls(snac *user)
1745 xs_html_attr("type", "number"), 1759 xs_html_attr("type", "number"),
1746 xs_html_attr("name", "purge_days"), 1760 xs_html_attr("name", "purge_days"),
1747 xs_html_attr("value", purge_days))), 1761 xs_html_attr("value", purge_days))),
1748 xs_html_tag("p", 1762 html_checkbox("drop_dm_from_unknown", L("Drop direct messages from people you don't follow"),
1749 xs_html_sctag("input", 1763 xs_is_true(d_dm_f_u)),
1750 xs_html_attr("type", "checkbox"), 1764 html_checkbox("bot", L("This account is a bot"),
1751 xs_html_attr("name", "drop_dm_from_unknown"), 1765 xs_is_true(bot)),
1752 xs_html_attr("id", "drop_dm_from_unknown"), 1766 html_checkbox("auto_boost", L("Auto-boost all mentions to this account"),
1753 xs_html_attr(xs_type(d_dm_f_u) == XSTYPE_TRUE ? "checked" : "", NULL)), 1767 xs_is_true(auto_boost)),
1754 xs_html_tag("label", 1768 html_checkbox("private", L("This account is private "
1755 xs_html_attr("for", "drop_dm_from_unknown"), 1769 "(posts are not shown through the web)"),
1756 xs_html_text(L("Drop direct messages from people you don't follow")))), 1770 xs_is_true(a_private)),
1757 xs_html_tag("p", 1771 html_checkbox("collapse_threads", L("Collapse top threads by default"),
1758 xs_html_sctag("input", 1772 xs_is_true(coll_thrds)),
1759 xs_html_attr("type", "checkbox"), 1773 html_checkbox("approve_followers", L("Follow requests must be approved"),
1760 xs_html_attr("name", "bot"), 1774 xs_is_true(pending)),
1761 xs_html_attr("id", "bot"), 1775 html_checkbox("show_contact_metrics", L("Publish follower and following metrics"),
1762 xs_html_attr(xs_type(bot) == XSTYPE_TRUE ? "checked" : "", NULL)), 1776 xs_is_true(show_foll)),
1763 xs_html_tag("label",
1764 xs_html_attr("for", "bot"),
1765 xs_html_text(L("This account is a bot")))),
1766 xs_html_tag("p",
1767 xs_html_sctag("input",
1768 xs_html_attr("type", "checkbox"),
1769 xs_html_attr("name", "auto_boost"),
1770 xs_html_attr("id", "auto_boost"),
1771 xs_html_attr(xs_is_true(auto_boost) ? "checked" : "", NULL)),
1772 xs_html_tag("label",
1773 xs_html_attr("for", "auto_boost"),
1774 xs_html_text(L("Auto-boost all mentions to this account")))),
1775 xs_html_tag("p",
1776 xs_html_sctag("input",
1777 xs_html_attr("type", "checkbox"),
1778 xs_html_attr("name", "private"),
1779 xs_html_attr("id", "private"),
1780 xs_html_attr(xs_type(a_private) == XSTYPE_TRUE ? "checked" : "", NULL)),
1781 xs_html_tag("label",
1782 xs_html_attr("for", "private"),
1783 xs_html_text(L("This account is private "
1784 "(posts are not shown through the web)")))),
1785 xs_html_tag("p",
1786 xs_html_sctag("input",
1787 xs_html_attr("type", "checkbox"),
1788 xs_html_attr("name", "collapse_threads"),
1789 xs_html_attr("id", "collapse_threads"),
1790 xs_html_attr(xs_is_true(coll_thrds) ? "checked" : "", NULL)),
1791 xs_html_tag("label",
1792 xs_html_attr("for", "collapse_threads"),
1793 xs_html_text(L("Collapse top threads by default")))),
1794 xs_html_tag("p",
1795 xs_html_sctag("input",
1796 xs_html_attr("type", "checkbox"),
1797 xs_html_attr("name", "approve_followers"),
1798 xs_html_attr("id", "approve_followers"),
1799 xs_html_attr(xs_is_true(pending) ? "checked" : "", NULL)),
1800 xs_html_tag("label",
1801 xs_html_attr("for", "approve_followers"),
1802 xs_html_text(L("Follow requests must be approved")))),
1803 xs_html_tag("p",
1804 xs_html_sctag("input",
1805 xs_html_attr("type", "checkbox"),
1806 xs_html_attr("name", "show_contact_metrics"),
1807 xs_html_attr("id", "show_contact_metrics"),
1808 xs_html_attr(xs_is_true(show_foll) ? "checked" : "", NULL)),
1809 xs_html_tag("label",
1810 xs_html_attr("for", "show_contact_metrics"),
1811 xs_html_text(L("Publish follower and following metrics")))),
1812 xs_html_tag("p", 1777 xs_html_tag("p",
1813 xs_html_text(L("Current location:")), 1778 xs_html_text(L("Current location:")),
1814 xs_html_sctag("br", NULL), 1779 xs_html_sctag("br", NULL),
@@ -2256,7 +2221,7 @@ static const xs_str* words_in_content(const xs_list *words, const xs_val *conten
2256/* returns a word that matches any of the words in content */ 2221/* returns a word that matches any of the words in content */
2257{ 2222{
2258 if (!xs_is_list(words) || !xs_is_string(content)) { 2223 if (!xs_is_list(words) || !xs_is_string(content)) {
2259 return NULL; 2224 return NULL;
2260 } 2225 }
2261 xs *c = xs_split(content, " "); 2226 xs *c = xs_split(content, " ");
2262 xs *sc = xs_list_sort(c, NULL); 2227 xs *sc = xs_list_sort(c, NULL);
@@ -2266,9 +2231,8 @@ static const xs_str* words_in_content(const xs_list *words, const xs_val *conten
2266 xs_list_foreach(words, wv) { 2231 xs_list_foreach(words, wv) {
2267 xs_list_foreach(sc, cv) { 2232 xs_list_foreach(sc, cv) {
2268 xs_tolower_i((xs_str*)cv); 2233 xs_tolower_i((xs_str*)cv);
2269 if(xs_str_in(cv, wv) != -1){ 2234 if(xs_str_in(cv, wv) != -1)
2270 return wv; 2235 return wv;
2271 }
2272 } 2236 }
2273 } 2237 }
2274 2238
@@ -3634,7 +3598,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
3634 continue; 3598 continue;
3635 3599
3636 const int scope = get_msg_visibility(msg); 3600 const int scope = get_msg_visibility(msg);
3637 if (user != NULL && scope != SCOPE_PUBLIC){ 3601 if (user != NULL && scope != SCOPE_PUBLIC) {
3638 /* is this message a non-public reply? */ 3602 /* is this message a non-public reply? */
3639 const char *irt = get_in_reply_to(msg); 3603 const char *irt = get_in_reply_to(msg);
3640 3604
@@ -3651,13 +3615,11 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
3651 } 3615 }
3652 } 3616 }
3653 /* hide non-public posts from /instance view */ 3617 /* hide non-public posts from /instance view */
3654 if (page != NULL && strcmp(page, "/instance") == 0 && scope != SCOPE_PUBLIC){ 3618 if (page != NULL && strcmp(page, "/instance") == 0 && scope != SCOPE_PUBLIC)
3655 continue; 3619 continue;
3656 }
3657 /* hide non-public posts viewed from outside */ 3620 /* hide non-public posts viewed from outside */
3658 if (read_only && (scope != SCOPE_PUBLIC && scope != SCOPE_UNLISTED)) { 3621 if (read_only && (scope != SCOPE_PUBLIC && scope != SCOPE_UNLISTED))
3659 continue; 3622 continue;
3660 }
3661 3623
3662 xs_html *entry = html_entry(user, msg, read_only, 0, v, (user && !hide_children) ? 0 : 1); 3624 xs_html *entry = html_entry(user, msg, read_only, 0, v, (user && !hide_children) ? 0 : 1);
3663 3625
@@ -4112,6 +4074,32 @@ xs_str *html_people_one(snac *user, const char *actor, const xs_list *list,
4112 return xs_html_render_s(html, "<!DOCTYPE html>\n"); 4074 return xs_html_render_s(html, "<!DOCTYPE html>\n");
4113} 4075}
4114 4076
4077void notify_filter(snac *user, const xs_dict *p_vars)
4078/* sets filter for notifications */
4079{
4080 const char *v;
4081 int likes_on = (v = xs_dict_get(p_vars, "likes_on")) ? strcmp(v, "on") == 0 : 0;
4082 int reacts_on = (v = xs_dict_get(p_vars, "reacts_on")) ? strcmp(v, "on") == 0 : 0;
4083 int ments_on = (v = xs_dict_get(p_vars, "mentions_on")) ? strcmp(v, "on") == 0 : 0;
4084 int ann_on = (v = xs_dict_get(p_vars, "announces_on")) ? strcmp(v, "on") == 0 : 0;
4085 int foll_on = (v = xs_dict_get(p_vars, "follows_on")) ? strcmp(v, "on") == 0 : 0;
4086 int unfoll_on = (v = xs_dict_get(p_vars, "unfollows_on")) ? strcmp(v, "on") == 0 : 0;
4087 int folreq_on = (v = xs_dict_get(p_vars, "folreqs_on")) ? strcmp(v, "on") == 0 : 0;
4088 int blocks_on = (v = xs_dict_get(p_vars, "blocks_on")) ? strcmp(v, "on") == 0 : 0;
4089 int polls_on = (v = xs_dict_get(p_vars, "polls_on")) ? strcmp(v, "on") == 0 : 0;
4090 xs_dict *filter = xs_dict_new();
4091 filter = xs_dict_set(filter, "likes", xs_stock(likes_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4092 filter = xs_dict_set(filter, "reacts", xs_stock(reacts_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4093 filter = xs_dict_set(filter, "mentions", xs_stock(ments_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4094 filter = xs_dict_set(filter, "announces", xs_stock(ann_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4095 filter = xs_dict_set(filter, "follows", xs_stock(foll_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4096 filter = xs_dict_set(filter, "unfollows", xs_stock(unfoll_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4097 filter = xs_dict_set(filter, "folreqs", xs_stock(folreq_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4098 filter = xs_dict_set(filter, "blocks", xs_stock(blocks_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4099 filter = xs_dict_set(filter, "polls", xs_stock(polls_on ? XSTYPE_TRUE : XSTYPE_FALSE));
4100 user->config = xs_dict_set(user->config, "notify_filter", filter);
4101}
4102
4115xs_str *html_notifications(snac *user, int skip, int show) 4103xs_str *html_notifications(snac *user, int skip, int show)
4116{ 4104{
4117 const char *proxy = NULL; 4105 const char *proxy = NULL;
@@ -4119,15 +4107,66 @@ xs_str *html_notifications(snac *user, int skip, int show)
4119 if (xs_is_true(xs_dict_get(srv_config, "proxy_media"))) 4107 if (xs_is_true(xs_dict_get(srv_config, "proxy_media")))
4120 proxy = user->actor; 4108 proxy = user->actor;
4121 4109
4122 xs *n_list = notify_list(user, skip, show); 4110 xs *n_list_unfilt = notify_list(user, skip, show);
4123 xs *n_time = notify_check_time(user, 0); 4111 xs *n_time = notify_check_time(user, 0);
4124 4112
4125 xs_html *body = html_user_body(user, 0); 4113 xs_html *body = html_user_body(user, 0);
4114 const xs_dict *n_filter = xs_dict_get(user->config, "notify_filter");
4115 if (!n_filter) {
4116 user->config = xs_dict_set(user->config, "notify_filter", xs_dict_new());
4117 n_filter = xs_dict_get(user->config, "notify_filter");
4118 }
4119 xs *n_list = notify_filter_list(user, n_list_unfilt);
4120 /* all filters are true by default */
4121 const xs_val *n_def = xs_stock( XSTYPE_TRUE );
4122 int n_likes_on = xs_is_true(xs_dict_get_def(n_filter, "likes", n_def));
4123 int n_reacts_on = xs_is_true(xs_dict_get_def(n_filter, "reacts", n_def));
4124 int n_ments_on = xs_is_true(xs_dict_get_def(n_filter, "mentions", n_def));
4125 int n_ann_on = xs_is_true(xs_dict_get_def(n_filter, "announces", n_def));
4126 int n_fol_on = xs_is_true(xs_dict_get_def(n_filter, "follows", n_def));
4127 int n_unfol_on = xs_is_true(xs_dict_get_def(n_filter, "unfollows", n_def));
4128 int n_folreq_on = xs_is_true(xs_dict_get_def(n_filter, "folreqs", n_def));
4129 int n_blocks_on = xs_is_true(xs_dict_get_def(n_filter, "blocks", n_def));
4130 int n_polls_on = xs_is_true(xs_dict_get_def(n_filter, "polls", n_def));
4126 4131
4127 xs_html *html = xs_html_tag("html", 4132 xs_html *html = xs_html_tag("html",
4128 html_user_head(user, NULL, NULL), 4133 html_user_head(user, NULL, NULL),
4129 body); 4134 body);
4130 4135
4136 xs *filter_notifs_action = xs_fmt("%s/admin/filter-notifications", user->actor);
4137 xs_html *notifs_form = xs_html_tag("form",
4138 xs_html_attr("autocomplete", "off"),
4139 xs_html_attr("method", "post"),
4140 xs_html_attr("action", filter_notifs_action),
4141 xs_html_attr("enctype", "multipart/form-data"),
4142 xs_html_attr("id", "filter"),
4143 xs_html_sctag("input",
4144 xs_html_attr("type", "hidden"),
4145 xs_html_attr("name", "hard-redir"),
4146 xs_html_attr("value", xs_fmt("%s/notifications", user->actor))),
4147 html_checkbox("likes_on", L("Likes"), n_likes_on),
4148 html_checkbox("reacts_on", L("Emoji reacts"), n_reacts_on),
4149 html_checkbox("mentions_on", L("Mentions"), n_ments_on),
4150 html_checkbox("announces_on", L("Announces"), n_ann_on),
4151 html_checkbox("follows_on", L("Follows"), n_fol_on),
4152 html_checkbox("unfollows_on", L("Unollows"), n_unfol_on),
4153 html_checkbox("folreqs_on", L("Follow requests"), n_folreq_on),
4154 html_checkbox("blocks_on", L("Blocks"), n_blocks_on),
4155 html_checkbox("polls_on", L("Polls"), n_polls_on),
4156 xs_html_sctag("input",
4157 xs_html_attr("type", "submit"),
4158 xs_html_attr("class", "button"),
4159 xs_html_attr("value", L("Save"))));
4160
4161 xs_html_add(body,
4162 xs_html_tag("p",
4163 xs_html_tag("div",
4164 xs_html_attr("class", "snac-notify-filter"),
4165 xs_html_tag("details",
4166 xs_html_tag("summary",
4167 xs_html_text(L("Notifications filter"))),
4168 notifs_form))));
4169
4131 xs *clear_all_action = xs_fmt("%s/admin/clear-notifications", user->actor); 4170 xs *clear_all_action = xs_fmt("%s/admin/clear-notifications", user->actor);
4132 4171
4133 xs_html_add(body, 4172 xs_html_add(body,
@@ -4205,14 +4244,17 @@ xs_str *html_notifications(snac *user, int skip, int show)
4205 xs *label_sanitized = sanitize(type); 4244 xs *label_sanitized = sanitize(type);
4206 const char *label = label_sanitized; 4245 const char *label = label_sanitized;
4207 4246
4208 if (strcmp(type, "Create") == 0) 4247 if (strcmp(type, "Create") == 0) {
4209 label = L("Mention"); 4248 label = L("Mention");
4249 }
4210 else 4250 else
4211 if (strcmp(type, "Update") == 0 && strcmp(utype, "Question") == 0) 4251 if (strcmp(type, "Update") == 0 && strcmp(utype, "Question") == 0) {
4212 label = L("Finished poll"); 4252 label = L("Finished poll");
4253 }
4213 else 4254 else
4214 if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0) 4255 if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0) {
4215 label = L("Unfollow"); 4256 label = L("Unfollow");
4257 }
4216 else 4258 else
4217 if (strcmp(type, "EmojiReact") == 0 || strcmp(type, "Like") == 0) { 4259 if (strcmp(type, "EmojiReact") == 0 || strcmp(type, "Like") == 0) {
4218 const char *content = xs_dict_get_path(noti, "msg.content"); 4260 const char *content = xs_dict_get_path(noti, "msg.content");
@@ -4227,14 +4269,19 @@ xs_str *html_notifications(snac *user, int skip, int show)
4227 isEmoji = 1; 4269 isEmoji = 1;
4228 4270
4229 if (xs_type(content) == XSTYPE_STRING) { 4271 if (xs_type(content) == XSTYPE_STRING) {
4272 if (!isEmoji && !n_likes_on)
4273 continue;
4230 xs *emoji = replace_shortnames(xs_dup(content), xs_dict_get_path(noti, "msg.tag"), 1, proxy); 4274 xs *emoji = replace_shortnames(xs_dup(content), xs_dict_get_path(noti, "msg.tag"), 1, proxy);
4231 wrk = xs_fmt("%s (%s&#xFE0F;)", isEmoji ? "EmojiReact" : "Like", emoji); 4275 wrk = xs_fmt("%s (%s&#xFE0F;)", isEmoji ? "EmojiReact" : "Like", emoji);
4232 label = wrk; 4276 label = wrk;
4233 } 4277 }
4234 } 4278 }
4235 else 4279 else
4236 if (strcmp(type, "Follow") == 0 && pending_check(user, actor_id)) 4280 if (strcmp(type, "Follow") == 0) {
4237 label = L("Follow Request"); 4281 if (pending_check(user, actor_id)) {
4282 label = L("Follow Request");
4283 }
4284 }
4238 4285
4239 xs *s_date = html_date_label(user, date); 4286 xs *s_date = html_date_label(user, date);
4240 4287
@@ -5835,6 +5882,12 @@ int html_post_handler(const xs_dict *req, const char *q_path,
5835 status = HTTP_STATUS_SEE_OTHER; 5882 status = HTTP_STATUS_SEE_OTHER;
5836 } 5883 }
5837 else 5884 else
5885 if (p_path && strcmp(p_path, "admin/filter-notifications") == 0) { /** **/
5886 notify_filter(&snac, p_vars);
5887 user_persist(&snac, 0);
5888 status = HTTP_STATUS_SEE_OTHER;
5889 }
5890 else
5838 if (p_path && strcmp(p_path, "admin/clear-notifications") == 0) { /** **/ 5891 if (p_path && strcmp(p_path, "admin/clear-notifications") == 0) { /** **/
5839 notify_clear(&snac); 5892 notify_clear(&snac);
5840 timeline_touch(&snac); 5893 timeline_touch(&snac);
diff --git a/snac.h b/snac.h
index 230505c..9815c78 100644
--- a/snac.h
+++ b/snac.h
@@ -277,6 +277,7 @@ void notify_add(snac *snac, const char *type, const char *utype,
277xs_dict *notify_get(snac *snac, const char *id); 277xs_dict *notify_get(snac *snac, const char *id);
278int notify_new_num(snac *snac); 278int notify_new_num(snac *snac);
279xs_list *notify_list(snac *snac, int skip, int show); 279xs_list *notify_list(snac *snac, int skip, int show);
280xs_list *notify_filter_list(snac *snac, xs_list *ids);
280void notify_clear(snac *snac); 281void notify_clear(snac *snac);
281 282
282xs_dict *markers_get(snac *snac, const xs_list *markers); 283xs_dict *markers_get(snac *snac, const xs_list *markers);