commit 4a2a05c
Merge pull request 'user-specified word mutes and matching' (#518) from byte/snac2:user_mutes into master Reviewed-on: https://codeberg.org/grunfink/snac2/pulls/518
2 files changed,
+96,
-1
M
html.c
+1,
-1
1@@ -2958,7 +2958,7 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req)
2 if (xs_is_null(object))
3 snac_log(snac, xs_fmt("malformed message: no 'id' field"));
4 else
5- if (timeline_admire(snac, object, actor, 1, xs_dup(msg)) == HTTP_STATUS_CREATED)
6+ if (timeline_admire(snac, object, actor, 1, msg) == HTTP_STATUS_CREATED)
7 snac_log(snac, xs_fmt("new '%s' %s %s", type, actor, object));
8 else
9 snac_log(snac, xs_fmt("repeated '%s' from %s to %s", type, actor, object));
M
html.c
+95,
-0
1@@ -16,6 +16,7 @@
2 #include "xs_url.h"
3 #include "xs_random.h"
4 #include "xs_http.h"
5+#include "xs_list_tools.h"
6
7 #include "snac.h"
8
9@@ -1864,6 +1865,38 @@ xs_html *html_top_controls(snac *user)
10 xs_html_attr("class", "button"),
11 xs_html_attr("value", L("Update hashtags")))))));
12
13+ xs *muted_words_action = xs_fmt("%s/admin/muted-words", user->actor);
14+ xs *muted_words = xs_join(xs_dict_get_def(user->config,
15+ "muted_words", xs_stock(XSTYPE_LIST)), "\n");
16+
17+ xs_html_add(top_controls,
18+ xs_html_tag("details",
19+ xs_html_tag("summary",
20+ xs_html_text(L("Muted words..."))),
21+ xs_html_tag("p",
22+ xs_html_text(L("One word per line, partial matches count"))),
23+ xs_html_tag("div",
24+ xs_html_attr("class", "snac-muted-words"),
25+ xs_html_tag("form",
26+ xs_html_attr("autocomplete", "off"),
27+ xs_html_attr("method", "post"),
28+ xs_html_attr("action", muted_words_action),
29+ xs_html_attr("enctype", "multipart/form-data"),
30+
31+ xs_html_tag("textarea",
32+ xs_html_attr("name", "muted_words"),
33+ xs_html_attr("cols", "40"),
34+ xs_html_attr("rows", "4"),
35+ xs_html_attr("placeholder", "nascar\nsuperbowl\nFIFA"),
36+ xs_html_text(muted_words)),
37+
38+ xs_html_tag("br", NULL),
39+
40+ xs_html_sctag("input",
41+ xs_html_attr("type", "submit"),
42+ xs_html_attr("class", "button"),
43+ xs_html_attr("value", L("Update muted words")))))));
44+
45 return top_controls;
46 }
47
48@@ -2144,6 +2177,30 @@ xs_html *html_entry_controls(snac *user, const char *actor,
49 }
50
51
52+static const xs_str* words_in_content(const xs_list *words, const xs_val *content)
53+/* returns a word that matches any of the words in content */
54+{
55+ if (!xs_is_list(words) || !xs_is_string(content)) {
56+ return NULL;
57+ }
58+ xs *c = xs_split(content, " ");
59+ xs *sc = xs_list_sort(c, NULL);
60+
61+ const xs_str *wv;
62+ const xs_str *cv;
63+ xs_list_foreach(words, wv) {
64+ xs_list_foreach(sc, cv) {
65+ xs_tolower_i((xs_str*)cv);
66+ if(xs_str_in(cv, wv) != -1){
67+ return wv;
68+ }
69+ }
70+ }
71+
72+ return NULL;
73+}
74+
75+
76 xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
77 int level, const char *md5, int hide_children)
78 {
79@@ -2438,6 +2495,17 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
80 xs_html_text(v),
81 xs_html_text(L(" [SENSITIVE CONTENT]"))));
82 }
83+ else
84+ if (user &&
85+ /* muted_words is all lowercase and sorted for performance */
86+ (v = words_in_content(xs_dict_get(user->config, "muted_words"),
87+ xs_dict_get(msg, "content"))) != NULL) {
88+ snac_debug(user, 1, xs_fmt("word %s muted by user preferences: %s", v, id));
89+ snac_content = xs_html_tag("details",
90+ xs_html_tag("summary",
91+ xs_html_text(L("Muted: ")),
92+ xs_html_text(v)));
93+ }
94 else {
95 snac_content = xs_html_tag("div", NULL);
96 }
97@@ -5813,6 +5881,33 @@ int html_post_handler(const xs_dict *req, const char *q_path,
98
99 status = HTTP_STATUS_SEE_OTHER;
100 }
101+ else
102+ if (p_path && strcmp(p_path, "admin/muted-words") == 0) {
103+ const char *words = xs_dict_get(p_vars, "muted_words");
104+
105+ if (xs_is_string(words)) {
106+ xs *new_words = xs_list_new();
107+ xs *l = xs_split(words, "\n");
108+ const char *v;
109+
110+ xs_list_foreach(l, v) {
111+ xs *s1 = xs_strip_i(xs_dup(v));
112+ s1 = xs_replace_i(s1, " ", "");
113+
114+ if (*s1 == '\0')
115+ continue;
116+
117+ xs *s2 = xs_utf8_to_lower(s1);
118+
119+ new_words = xs_list_insert_sorted(new_words, s2);
120+ }
121+
122+ snac.config = xs_dict_set(snac.config, "muted_words", new_words);
123+ user_persist(&snac, 0);
124+ }
125+
126+ status = HTTP_STATUS_SEE_OTHER;
127+ }
128
129 if (status == HTTP_STATUS_SEE_OTHER) {
130 const char *hard_redir = xs_dict_get(p_vars, "hard-redir");