diff --git a/daemon.py b/daemon.py index 8e80f21b1..39cdb2cbb 100644 --- a/daemon.py +++ b/daemon.py @@ -122,6 +122,7 @@ from inbox import save_post_to_inbox_queue from inbox import populate_replies from inbox import receive_edit_to_post from followerSync import update_followers_sync_cache +from follow import pending_followers_timeline_json from follow import follower_approval_active from follow import is_following_actor from follow import get_following_feed @@ -17383,6 +17384,60 @@ class PubServer(BaseHTTPRequestHandler): self._write(msg) return + if self.path.startswith('/users/') and \ + '/pendingFollowers' in self.path: + pending_collection_authorized = authorized + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + page_number = 1 + if '?page=' in self.path: + page_number_str = self.path.split('?page=')[1] + if ';' in page_number_str: + page_number_str = page_number_str.split(';')[0] + if page_number_str.isdigit(): + page_number = int(page_number_str) + # show pending followers collection for the nickname + actor = \ + local_actor_url(self.server.http_prefix, + nickname, self.server.domain_full) + actor += '/pendingFollowers' + pending_json = { + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + "id": actor, + "type": "OrderedCollection", + "name": nickname + "'s Pending Followers", + "orderedItems": [] + } + if self._has_accept(calling_domain) and \ + pending_collection_authorized: + if self.server.debug: + print('Preparing pending followers collection') + + if self.server.debug: + print('Pending followers collection for account: ' + + nickname) + base_dir = self.server.base_dir + pending_json = \ + pending_followers_timeline_json(actor, base_dir, nickname, + self.server.domain) + msg_str = json.dumps(pending_json, + ensure_ascii=False) + msg_str = self._convert_domains(calling_domain, + referer_domain, + msg_str) + msg = msg_str.encode('utf-8') + msglen = len(msg) + accept_str = self.headers['Accept'] + protocol_str = \ + get_json_content_from_accept(accept_str) + self._set_headers(protocol_str, msglen, + None, calling_domain, False) + self._write(msg) + return + # wanted items collection for this instance # this is only accessible to instance members or to # other instances which present an authorization token diff --git a/follow.py b/follow.py index d06d9ea94..c56b25468 100644 --- a/follow.py +++ b/follow.py @@ -1555,3 +1555,35 @@ def remove_follower(base_dir: str, print('EX: remove_follower unable to write followers ' + followers_filename) return True + + +def pending_followers_timeline_json(actor: str, base_dir: str, + nickname: str, domain: str) -> {}: + """Returns pending followers collection for an account + https://codeberg.org/fediverse/fep/src/branch/main/fep/4ccd/fep-4ccd.md + """ + result_json = { + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + "id": actor, + "type": "OrderedCollection", + "name": nickname + "'s Pending Followers", + "orderedItems": [] + } + + follow_requests_filename = \ + acct_dir(base_dir, nickname, domain) + '/followrequests.txt' + if os.path.isfile(follow_requests_filename): + with open(follow_requests_filename, 'r', + encoding='utf-8') as req_file: + for follower_handle in req_file: + if len(follower_handle) == 0: + continue + follower_handle = remove_eol(follower_handle) + foll_json = { + "type": "Follow", + "actor": follower_handle + } + result_json['orderedItems'].append(foll_json) + return result_json diff --git a/person.py b/person.py index c03da291b..3cba8d394 100644 --- a/person.py +++ b/person.py @@ -435,7 +435,9 @@ def _create_person_base(base_dir: str, nickname: str, domain: str, port: int, 'id': person_id + '/endpoints', 'sharedInbox': http_prefix + '://' + domain + '/inbox', 'offers': person_id + '/offers', - 'wanted': person_id + '/wanted' + 'wanted': person_id + '/wanted', + 'blocked': person_id + '/blocked', + 'pendingFollowers': person_id + '/pendingFollowers' }, 'featured': person_id + '/collections/featured', 'featuredTags': person_id + '/collections/tags', @@ -805,6 +807,10 @@ def person_upgrade_actor(base_dir: str, person_json: {}, update_actor = True if person_json.get('endpoints'): + if not person_json['endpoints'].get('pendingFollowers'): + person_json['endpoints']['pendingFollowers'] = \ + person_json['id'] + '/pendingFollowers' + update_actor = True if not person_json['endpoints'].get('blocked'): person_json['endpoints']['blocked'] = \ person_json['id'] + '/blocked'