Explorar el Código

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

Reviewed-on: https://codeberg.org/zen/snac2/pulls/11
Oliver hace 11 meses
padre
commit
e50a6ba146
Se han modificado 6 ficheros con 128 adiciones y 1 borrados
  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.
 Added nodeinfo 2.1 support.
 
 
+Fixed boosts from the command line not showing in the public timeline (contributed by xvello).
+
 ## 2.81
 ## 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.
 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)
 void notify(snac *snac, const char *type, const char *utype, const char *actor, const xs_dict *msg)
 /* notifies the user of relevant events */
 /* 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
     else
         snac_log(user, xs_fmt("unexpected user q_item type '%s'", type));
         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)
 int was_question_voted(snac *user, const char *id)
 /* returns true if the user voted in this poll */
 /* 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
 If you set this checkbox, your text will not be sent when you
 push the Post button, but stored for later modification in
 push the Post button, but stored for later modification in
 the "Drafts" section.
 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...
 .It Scheduled post...
 This dropdown menu allows setting a date and time for the
 This dropdown menu allows setting a date and time for the
 post publication.
 post publication.
@@ -188,6 +192,9 @@ can be selected here.
 .It Time zone
 .It Time zone
 The time zone the user is on (default: UTC). Only
 The time zone the user is on (default: UTC). Only
 used for scheduled posts.
 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
 .It Password
 Write the same string in these two fields to change your
 Write the same string in these two fields to change your
 password. Don't write anything if you don't want to do this.
 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"
         "unfollow {basedir} {uid} {actor}     Unfollows an actor\n"
         "request {basedir} {uid} {url}        Requests an object\n"
         "request {basedir} {uid} {url}        Requests an object\n"
         "insert {basedir} {uid} {url}         Requests an object and inserts it into the timeline\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"
         "actor {basedir} [{uid}] {url}        Requests an actor\n"
         "note {basedir} {uid} {text} [files...] Sends a note with optional attachments\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"
         "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"
         "verify_links {basedir} {uid}         Verifies a user's links (in the metadata)\n"
         "search {basedir} {uid} {regex}       Searches posts by content\n"
         "search {basedir} {uid} {regex}       Searches posts by content\n"
         "export_csv {basedir} {uid}           Exports followers, lists, MUTEd and bookmarks to CSV\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"
         "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"
         "migrate {basedir} {uid}              Migrates to the account defined as the alias\n"
         "import_csv {basedir} {uid}           Imports data from CSV files\n"
         "import_csv {basedir} {uid}           Imports data from CSV files\n"
@@ -494,6 +495,7 @@ int main(int argc, char *argv[])
 
 
         if (msg != NULL) {
         if (msg != NULL) {
             enqueue_message(&snac, msg);
             enqueue_message(&snac, msg);
+            timeline_admire(&snac, xs_dict_get(msg, "object"), snac.actor, 0);
 
 
             if (dbglevel) {
             if (dbglevel) {
                 xs_json_dump(msg, 4, stdout);
                 xs_json_dump(msg, 4, stdout);
@@ -730,6 +732,12 @@ int main(int argc, char *argv[])
         return 0;
         return 0;
     }
     }
 
 
+    if (strcmp(cmd, "collect_replies") == 0) { /** **/
+        enqueue_collect_replies(&snac, url);
+
+        return 0;
+    }
+
     if (strcmp(cmd, "insert") == 0) { /** **/
     if (strcmp(cmd, "insert") == 0) { /** **/
         int status;
         int status;
         xs *data = NULL;
         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_actor_refresh(snac *user, const char *actor, int forward_secs);
 void enqueue_webmention(const xs_dict *msg);
 void enqueue_webmention(const xs_dict *msg);
 void enqueue_notify_webhook(snac *user, const xs_dict *noti, int retries);
 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);
 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);
 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_atto(const xs_dict *msg);
 const char *get_in_reply_to(const xs_dict *msg);
 const char *get_in_reply_to(const xs_dict *msg);
 xs_list *get_attachments(const xs_dict *msg);
 xs_list *get_attachments(const xs_dict *msg);