Просмотр исходного кода

Merge pull request 'master' (#11) from grunfink/snac2:master into master

Reviewed-on: https://codeberg.org/zen/snac2/pulls/11
Oliver 11 месяцев назад
Родитель
Сommit
e50a6ba146
6 измененных файлов с 128 добавлено и 1 удалено
  1. 2 0
      RELEASE_NOTES.md
  2. 94 0
      activitypub.c
  3. 13 0
      data.c
  4. 7 0
      doc/snac.1
  5. 9 1
      main.c
  6. 3 0
      snac.h

+ 2 - 0
RELEASE_NOTES.md

@@ -12,6 +12,8 @@ Mastodon API: Fixed repeated entries in timelines.
 
 Added nodeinfo 2.1 support.
 
+Fixed boosts from the command line not showing in the public timeline (contributed by xvello).
+
 ## 2.81
 
 If the `propagate_local_purge` configuration variable is set to `true` in `server.json`, purged local posts generate a `Delete` activity that is sent everywhere, instead of only deleted from the filesystem.

+ 94 - 0
activitypub.c

@@ -936,6 +936,94 @@ xs_str *process_tags(snac *snac, const char *content, xs_list **tag)
 }
 
 
+void collect_replies(snac *user, const char *id)
+/* collects all replies for a post */
+{
+    xs *obj = NULL;
+
+    if (!valid_status(object_get(id, &obj))) {
+        snac_debug(user, 1, xs_fmt("collect_replies: object '%s' is not here", id));
+        return;
+    }
+
+    const char *next = xs_dict_get_path(obj, "replies.first.next");
+    if (!xs_is_string(next)) {
+        snac_debug(user, 1, xs_fmt("collect_replies: object '%s' does not have a replies.first.next URL", id));
+        return;
+    }
+
+    /* pick the first level replies (may be empty) */
+    const xs_list *level0_replies = xs_dict_get_path(obj, "replies.first.items");
+
+    xs *reply_obj = NULL;
+
+    if (!valid_status(object_get(next, &reply_obj))) {
+        if (!valid_status(activitypub_request(user, next, &reply_obj))) {
+            snac_debug(user, 1, xs_fmt("collect_replies: cannot get replies object '%s'", next));
+            return;
+        }
+    }
+
+    const xs_list *level1_replies = xs_dict_get(reply_obj, "items");
+    if (!xs_is_list(level1_replies)) {
+        snac_debug(user, 1, xs_fmt("collect_replies: cannot get reply items from object '%s'", next));
+        return;
+    }
+
+    xs *items = NULL;
+
+    if (xs_is_list(level0_replies))
+        items = xs_list_cat(xs_dup(level0_replies), level1_replies);
+    else
+        items = xs_dup(level1_replies);
+
+    const xs_val *v;
+
+    xs_list_foreach(items, v) {
+        xs *reply = NULL;
+
+        if (xs_is_string(v)) {
+            /* request the object */
+            if (!valid_status(object_get(v, &reply))) {
+                if (!valid_status(activitypub_request(user, v, &reply))) {
+                    snac_debug(user, 1, xs_fmt("collect_replies: error requesting object '%s'", v));
+                    continue;
+                }
+            }
+        }
+        else
+        if (xs_is_dict(v)) {
+            /* actually the post object */
+            reply = xs_dup(v);
+        }
+
+        if (!xs_is_dict(reply))
+            continue;
+
+        const char *id      = xs_dict_get(reply, "id");
+        const char *type    = xs_dict_get(reply, "type");
+        const char *attr_to = get_atto(reply);
+
+        if (!xs_is_string(id) || !xs_is_string(type) || !xs_is_string(attr_to))
+            continue;
+
+        if (!xs_match(type, POSTLIKE_OBJECT_TYPE))
+            continue;
+
+        if (timeline_here(user, id)) {
+            snac_debug(user, 1, xs_fmt("collect_replies: item already in timeline %s", id));
+            continue;
+        }
+
+        enqueue_actor_refresh(user, attr_to, 0);
+
+        timeline_add(user, id, reply);
+
+        snac_log(user, xs_fmt("new '%s' (collect_replies) %s %s", type, attr_to, id));
+    }
+}
+
+
 void notify(snac *snac, const char *type, const char *utype, const char *actor, const xs_dict *msg)
 /* notifies the user of relevant events */
 {
@@ -2826,6 +2914,12 @@ void process_user_queue_item(snac *user, xs_dict *q_item)
             }
         }
     }
+    else
+    if (strcmp(type, "collect_replies") == 0) {
+        const char *post = xs_dict_get(q_item, "message");
+
+        collect_replies(user, post);
+    }
     else
         snac_log(user, xs_fmt("unexpected user q_item type '%s'", type));
 }

+ 13 - 0
data.c

@@ -3576,6 +3576,19 @@ void enqueue_notify_webhook(snac *user, const xs_dict *noti, int retries)
 }
 
 
+void enqueue_collect_replies(snac *user, const char *post)
+/* enqueues a collect replies request */
+{
+    xs *qmsg = _new_qmsg("collect_replies", post, 0);
+    const char *ntid = xs_dict_get(qmsg, "ntid");
+    xs *fn = xs_fmt("%s/queue/%s.json", user->basedir, ntid);
+
+    qmsg = _enqueue_put(fn, qmsg);
+
+    snac_debug(user, 1, xs_fmt("enqueue_collect_replies %s", post));
+}
+
+
 int was_question_voted(snac *user, const char *id)
 /* returns true if the user voted in this poll */
 {

+ 7 - 0
doc/snac.1

@@ -71,6 +71,10 @@ standalone one.
 If you set this checkbox, your text will not be sent when you
 push the Post button, but stored for later modification in
 the "Drafts" section.
+.It Language
+A dropdown to select which language your post will be written
+in. This control only appears after you configure the set of
+languages you expect to use in the User Settings (see below).
 .It Scheduled post...
 This dropdown menu allows setting a date and time for the
 post publication.
@@ -188,6 +192,9 @@ can be selected here.
 .It Time zone
 The time zone the user is on (default: UTC). Only
 used for scheduled posts.
+.It Languages you usually post in
+Fill this string with the ISO 639 Language Codes you expect to
+write your posts in, space-separated (example: en fr pt_BR).
 .It Password
 Write the same string in these two fields to change your
 password. Don't write anything if you don't want to do this.

+ 9 - 1
main.c

@@ -39,6 +39,7 @@ int usage(const char *cmd)
         "unfollow {basedir} {uid} {actor}     Unfollows an actor\n"
         "request {basedir} {uid} {url}        Requests an object\n"
         "insert {basedir} {uid} {url}         Requests an object and inserts it into the timeline\n"
+        "collect_replies {basedir} {uid} {url} Collects all replies from a post\n"
         "actor {basedir} [{uid}] {url}        Requests an actor\n"
         "note {basedir} {uid} {text} [files...] Sends a note with optional attachments\n"
         "note_unlisted {basedir} {uid} {text} [files...] Sends an unlisted note with optional attachments\n"
@@ -61,7 +62,7 @@ int usage(const char *cmd)
         "verify_links {basedir} {uid}         Verifies a user's links (in the metadata)\n"
         "search {basedir} {uid} {regex}       Searches posts by content\n"
         "export_csv {basedir} {uid}           Exports followers, lists, MUTEd and bookmarks to CSV\n"
-        "export_posts {basedir} {iod}         Exports all posts to outbox.json\n"
+        "export_posts {basedir} {uid}         Exports all posts to outbox.json\n"
         "alias {basedir} {uid} {account}      Sets account (@user@host or actor url) as an alias\n"
         "migrate {basedir} {uid}              Migrates to the account defined as the alias\n"
         "import_csv {basedir} {uid}           Imports data from CSV files\n"
@@ -494,6 +495,7 @@ int main(int argc, char *argv[])
 
         if (msg != NULL) {
             enqueue_message(&snac, msg);
+            timeline_admire(&snac, xs_dict_get(msg, "object"), snac.actor, 0);
 
             if (dbglevel) {
                 xs_json_dump(msg, 4, stdout);
@@ -730,6 +732,12 @@ int main(int argc, char *argv[])
         return 0;
     }
 
+    if (strcmp(cmd, "collect_replies") == 0) { /** **/
+        enqueue_collect_replies(&snac, url);
+
+        return 0;
+    }
+
     if (strcmp(cmd, "insert") == 0) { /** **/
         int status;
         xs *data = NULL;

+ 3 - 0
snac.h

@@ -297,6 +297,7 @@ void enqueue_verify_links(snac *user);
 void enqueue_actor_refresh(snac *user, const char *actor, int forward_secs);
 void enqueue_webmention(const xs_dict *msg);
 void enqueue_notify_webhook(snac *user, const xs_dict *noti, int retries);
+void enqueue_collect_replies(snac *user, const char *post);
 
 int was_question_voted(snac *user, const char *id);
 
@@ -334,6 +335,8 @@ const char *default_avatar_base64(void);
 
 xs_str *process_tags(snac *snac, const char *content, xs_list **tag);
 
+void collect_replies(snac *user, const char *id);
+
 const char *get_atto(const xs_dict *msg);
 const char *get_in_reply_to(const xs_dict *msg);
 xs_list *get_attachments(const xs_dict *msg);