Votes on questions are a type of DM

See https://socialhub.activitypub.rocks/t/votes-on-question-activities/2880
merge-requests/30/head
Bob Mottram 2023-01-12 10:45:39 +00:00
parent 0626ba32d5
commit 212bdacdb3
3 changed files with 127 additions and 90 deletions

View File

@ -674,30 +674,35 @@ class PubServer(BaseHTTPRequestHandler):
nickname, nickname,
self.server.domain_full, self.server.domain_full,
self.server.person_cache) self.server.person_cache)
reply_to_nickname = get_nickname_from_actor(in_reply_to)
reply_to_domain, reply_to_port = get_domain_from_actor(in_reply_to)
reply_to_domain_full = get_full_domain(reply_to_domain, reply_to_port)
mentions_str = '@' + reply_to_nickname + '@' + reply_to_domain_full
message_json = \ message_json = \
create_public_post(self.server.base_dir, create_direct_message_post(self.server.base_dir, nickname,
nickname, self.server.domain, self.server.port,
self.server.domain, self.server.port, self.server.http_prefix,
self.server.http_prefix, mentions_str + ' ' + answer,
answer, False, False, False, False,
comments_enabled, comments_enabled,
attach_image_filename, media_type, attach_image_filename,
image_description, city, media_type, image_description, city,
in_reply_to, in_reply_to, in_reply_to_atom_uri,
in_reply_to_atom_uri, subject, self.server.debug,
subject, schedule_post,
schedule_post, event_date, event_time,
event_date, event_end_time,
event_time, event_end_time, location, self.server.system_language,
location, False, conversation_id,
self.server.system_language, self.server.low_bandwidth,
conversation_id, self.server.content_license_url,
self.server.low_bandwidth, languages_understood, False,
self.server.content_license_url, self.server.translate)
languages_understood,
self.server.translate)
if message_json: if message_json:
# NOTE: content and contentMap are not required, but we will keep
# them in there so that the post does not get filtered out by
# inbox processing.
# name field contains the answer # name field contains the answer
message_json['object']['name'] = answer message_json['object']['name'] = answer
if self._post_to_outbox(message_json, if self._post_to_outbox(message_json,

View File

@ -119,6 +119,7 @@ from posts import send_signed_json
from posts import send_to_followers_thread from posts import send_to_followers_thread
from webapp_post import individual_post_as_html from webapp_post import individual_post_as_html
from question import question_update_votes from question import question_update_votes
from question import is_vote
from media import replace_you_tube from media import replace_you_tube
from media import replace_twitter from media import replace_twitter
from git import is_git_patch from git import is_git_patch
@ -4424,8 +4425,33 @@ def _inbox_after_initial(server, inbox_start_time,
post_json_object = message_json['post'] post_json_object = message_json['post']
else: else:
post_json_object = message_json post_json_object = message_json
nickname = handle.split('@')[0] nickname = handle.split('@')[0]
if is_vote(base_dir, nickname, domain, post_json_object):
_receive_question_vote(server, base_dir, nickname, domain,
http_prefix, handle, debug,
post_json_object, recent_posts_cache,
session, session_onion, session_i2p,
onion_domain, i2p_domain, port,
federation_list, send_threads, post_log,
cached_webfingers, person_cache,
signing_priv_key_pem,
max_recent_posts, translate,
allow_deletion,
yt_replace_domain,
twitter_replacement_domain,
peertube_instances,
allow_local_network_access,
theme_name, system_language,
max_like_count,
cw_lists, lists_enabled,
bold_reading, dogwhistles,
server.min_images_for_accounts)
fitness_performance(inbox_start_time, server.fitness,
'INBOX', '_receive_question_vote',
debug)
inbox_start_time = time.time()
json_obj = None json_obj = None
domain_full = get_full_domain(domain, port) domain_full = get_full_domain(domain, port)
if _valid_post_content(base_dir, nickname, domain, if _valid_post_content(base_dir, nickname, domain,
@ -4495,30 +4521,6 @@ def _inbox_after_initial(server, inbox_start_time,
debug) debug)
inbox_start_time = time.time() inbox_start_time = time.time()
_receive_question_vote(server, base_dir, nickname, domain,
http_prefix, handle, debug,
post_json_object, recent_posts_cache,
session, session_onion, session_i2p,
onion_domain, i2p_domain, port,
federation_list, send_threads, post_log,
cached_webfingers, person_cache,
signing_priv_key_pem,
max_recent_posts, translate,
allow_deletion,
yt_replace_domain,
twitter_replacement_domain,
peertube_instances,
allow_local_network_access,
theme_name, system_language,
max_like_count,
cw_lists, lists_enabled,
bold_reading, dogwhistles,
server.min_images_for_accounts)
fitness_performance(inbox_start_time, server.fitness,
'INBOX', '_receive_question_vote',
debug)
inbox_start_time = time.time()
is_reply_to_muted_post = False is_reply_to_muted_post = False
if not is_group: if not is_group:

View File

@ -15,52 +15,80 @@ from utils import has_object_dict
from utils import text_in_file from utils import text_in_file
def is_vote(base_dir: str, nickname: str, domain: str,
post_json_object: {}) -> bool:
""" is the given post a vote on a Question?
"""
post_obj = post_json_object
if has_object_dict(post_json_object):
post_obj = post_json_object['object']
if not post_obj.get('inReplyTo'):
return False
if not isinstance(post_obj['inReplyTo'], str):
return False
if not post_obj.get('name'):
return False
# is the replied to post a Question?
in_reply_to = post_obj['inReplyTo']
question_post_filename = \
locate_post(base_dir, nickname, domain, in_reply_to)
if not question_post_filename:
return False
question_json = load_json(question_post_filename)
if not question_json:
return False
if not has_object_dict(question_json):
return False
if not question_json['object'].get('type'):
return False
if question_json['type'] != 'Question':
return False
# does the question have options?
if not question_json['object'].get('oneOf'):
return False
if not isinstance(question_json['object']['oneOf'], list):
return False
# does the reply name field match any possible question option?
reply_vote = post_json_object['name']
found_answer_json = None
for possible_answer in question_json['object']['oneOf']:
if not possible_answer.get('name'):
continue
if possible_answer['name'] == reply_vote:
found_answer_json = possible_answer
break
if not found_answer_json:
return False
return True
def question_update_votes(base_dir: str, nickname: str, domain: str, def question_update_votes(base_dir: str, nickname: str, domain: str,
reply_json: {}) -> ({}, str): reply_json: {}) -> ({}, str):
""" For a given reply update the votes on a question """ For a given reply update the votes on a question
Returns the question json object if the vote totals were changed Returns the question json object if the vote totals were changed
""" """
if not has_object_dict(reply_json): if not is_vote(base_dir, nickname, domain, reply_json):
return None, None return None, None
if not reply_json['object'].get('inReplyTo'):
return None, None post_obj = reply_json
if not reply_json['object']['inReplyTo']: if has_object_dict(reply_json):
return None, None post_obj = reply_json['object']
if not isinstance(reply_json['object']['inReplyTo'], str): reply_vote = post_obj['name']
return None, None
if not reply_json['object'].get('name'): in_reply_to = post_obj['inReplyTo']
return None, None
in_reply_to = reply_json['object']['inReplyTo']
question_post_filename = \ question_post_filename = \
locate_post(base_dir, nickname, domain, in_reply_to) locate_post(base_dir, nickname, domain, in_reply_to)
if not question_post_filename: if not question_post_filename:
return None, None return None, None
question_json = load_json(question_post_filename) question_json = load_json(question_post_filename)
if not question_json: if not question_json:
return None, None return None, None
if not has_object_dict(question_json):
return None, None
if not question_json['object'].get('type'):
return None, None
if question_json['type'] != 'Question':
return None, None
if not question_json['object'].get('oneOf'):
return None, None
if not isinstance(question_json['object']['oneOf'], list):
return None, None
if not question_json['object'].get('content'):
return None, None
reply_vote = reply_json['object']['name']
# does the reply name field match any possible question option?
found_answer = None, None
for possible_answer in question_json['object']['oneOf']:
if not possible_answer.get('name'):
continue
if possible_answer['name'] == reply_vote:
found_answer = possible_answer
break
if not found_answer:
return None, None
# update the voters file # update the voters file
voters_file_separator = ';;;' voters_file_separator = ';;;'
voters_filename = question_post_filename.replace('.json', '.voters') voters_filename = question_post_filename.replace('.json', '.voters')
@ -71,7 +99,7 @@ def question_update_votes(base_dir: str, nickname: str, domain: str,
encoding='utf-8') as voters_file: encoding='utf-8') as voters_file:
voters_file.write(reply_json['actor'] + voters_file.write(reply_json['actor'] +
voters_file_separator + voters_file_separator +
found_answer + '\n') reply_vote + '\n')
except OSError: except OSError:
print('EX: unable to write voters file ' + voters_filename) print('EX: unable to write voters file ' + voters_filename)
else: else:
@ -82,7 +110,7 @@ def question_update_votes(base_dir: str, nickname: str, domain: str,
encoding='utf-8') as voters_file: encoding='utf-8') as voters_file:
voters_file.write(reply_json['actor'] + voters_file.write(reply_json['actor'] +
voters_file_separator + voters_file_separator +
found_answer + '\n') reply_vote + '\n')
except OSError: except OSError:
print('EX: unable to append to voters file ' + voters_filename) print('EX: unable to append to voters file ' + voters_filename)
else: else:
@ -96,7 +124,7 @@ def question_update_votes(base_dir: str, nickname: str, domain: str,
if vote_line.startswith(reply_json['actor'] + if vote_line.startswith(reply_json['actor'] +
voters_file_separator): voters_file_separator):
new_vote_line = reply_json['actor'] + \ new_vote_line = reply_json['actor'] + \
voters_file_separator + found_answer + '\n' voters_file_separator + reply_vote + '\n'
if vote_line == new_vote_line: if vote_line == new_vote_line:
break break
save_voters_file = True save_voters_file = True
@ -114,6 +142,7 @@ def question_update_votes(base_dir: str, nickname: str, domain: str,
voters_filename) voters_filename)
else: else:
return None, None return None, None
# update the vote counts # update the vote counts
question_totals_changed = False question_totals_changed = False
for possible_answer in question_json['object']['oneOf']: for possible_answer in question_json['object']['oneOf']:
@ -131,25 +160,26 @@ def question_update_votes(base_dir: str, nickname: str, domain: str,
question_totals_changed = True question_totals_changed = True
if not question_totals_changed: if not question_totals_changed:
return None, None return None, None
# save the question with altered totals # save the question with altered totals
save_json(question_json, question_post_filename) save_json(question_json, question_post_filename)
return question_json, question_post_filename return question_json, question_post_filename
def is_question(post_object_json: {}) -> bool: def is_question(post_json_object: {}) -> bool:
""" is the given post a question? """ is the given post a question?
""" """
if post_object_json['type'] != 'Create' and \ if post_json_object['type'] != 'Create' and \
post_object_json['type'] != 'Update': post_json_object['type'] != 'Update':
return False return False
if not has_object_dict(post_object_json): if not has_object_dict(post_json_object):
return False return False
if not post_object_json['object'].get('type'): if not post_json_object['object'].get('type'):
return False return False
if post_object_json['object']['type'] != 'Question': if post_json_object['object']['type'] != 'Question':
return False return False
if not post_object_json['object'].get('oneOf'): if not post_json_object['object'].get('oneOf'):
return False return False
if not isinstance(post_object_json['object']['oneOf'], list): if not isinstance(post_json_object['object']['oneOf'], list):
return False return False
return True return True