diff --git a/acceptreject.py b/acceptreject.py index 0e100173f..788848667 100644 --- a/acceptreject.py +++ b/acceptreject.py @@ -14,7 +14,7 @@ import time from posts import send_signed_json from flags import has_group_type from flags import url_permitted -from utils import get_status_number +from status import get_status_number from utils import get_attributed_to from utils import get_user_paths from utils import text_in_file diff --git a/announce.py b/announce.py index 5a49cc6f7..0da6bf1ee 100644 --- a/announce.py +++ b/announce.py @@ -12,6 +12,7 @@ __module_group__ = "ActivityPub" import os from flags import has_group_type from flags import url_permitted +from status import get_status_number from utils import text_in_file from utils import get_user_paths from utils import has_object_string_object @@ -20,7 +21,6 @@ from utils import remove_domain_port from utils import remove_id_ending from utils import has_users_path from utils import get_full_domain -from utils import get_status_number from utils import create_outbox_dir from utils import get_nickname_from_actor from utils import get_domain_from_actor diff --git a/auth.py b/auth.py index 8c51fdb52..90abf1f2c 100644 --- a/auth.py +++ b/auth.py @@ -18,7 +18,7 @@ from utils import data_dir from utils import has_users_path from utils import text_in_file from utils import remove_eol -from utils import date_utcnow +from timeFunctions import date_utcnow def _hash_password(password: str) -> str: diff --git a/blocking.py b/blocking.py index 66891993a..ab9320ca1 100644 --- a/blocking.py +++ b/blocking.py @@ -16,12 +16,12 @@ from session import create_session from flags import is_evil from flags import is_quote_toot from quote import get_quote_toot_url +from timeFunctions import date_utcnow +from timeFunctions import date_from_string_format from utils import get_user_paths from utils import contains_statuses from utils import data_dir from utils import string_contains -from utils import date_from_string_format -from utils import date_utcnow from utils import remove_eol from utils import has_object_string from utils import has_object_string_object diff --git a/blog.py b/blog.py index d8309697f..273d531d9 100644 --- a/blog.py +++ b/blog.py @@ -16,11 +16,11 @@ from webapp_utils import html_footer from webapp_utils import get_post_attachments_as_html from webapp_utils import edit_text_area from webapp_media import add_embedded_elements +from timeFunctions import date_from_string_format from utils import replace_strings from utils import data_dir from utils import remove_link_tracking from utils import get_url_from_post -from utils import date_from_string_format from utils import get_attributed_to from utils import remove_eol from utils import text_in_file diff --git a/cache.py b/cache.py index 46143de8c..48ceec02f 100644 --- a/cache.py +++ b/cache.py @@ -26,9 +26,9 @@ from utils import load_json from utils import save_json from utils import get_file_case_insensitive from utils import get_user_paths -from utils import date_utcnow -from utils import date_from_string_format from utils import get_image_extensions +from timeFunctions import date_from_string_format +from timeFunctions import date_utcnow from content import remove_script diff --git a/categories.py b/categories.py index 842eb3141..df6bff65c 100644 --- a/categories.py +++ b/categories.py @@ -9,9 +9,9 @@ __module_group__ = "RSS Feeds" import os import datetime +from timeFunctions import date_utcnow +from timeFunctions import date_epoch from utils import data_dir -from utils import date_utcnow -from utils import date_epoch from utils import replace_strings MAX_TAG_LENGTH = 42 diff --git a/content.py b/content.py index a6e295aa8..b78098957 100644 --- a/content.py +++ b/content.py @@ -15,6 +15,7 @@ import email.parser import urllib.parse from shutil import copyfile from dateutil.parser import parse +from timeFunctions import convert_published_to_local_timezone from flags import is_pgp_encrypted from flags import contains_pgp_public_key from flags import is_float @@ -31,7 +32,6 @@ from utils import binary_is_image from utils import get_content_from_post from utils import get_full_domain from utils import get_user_paths -from utils import convert_published_to_local_timezone from utils import has_object_dict from utils import valid_hash_tag from utils import dangerous_svg diff --git a/daemon.py b/daemon.py index ee00af8d5..3cfc13aa9 100644 --- a/daemon.py +++ b/daemon.py @@ -50,13 +50,13 @@ from categories import load_city_hashtags from categories import update_hashtag_categories from languages import load_default_post_languages from searchable import load_searchable_by_default +from timeFunctions import load_account_timezones from utils import set_accounts_data_dir from utils import data_dir from utils import check_bad_path from utils import acct_handle_dir from utils import load_reverse_timeline from utils import load_min_images_for_accounts -from utils import load_account_timezones from utils import load_translations_from_file from utils import load_bold_reading from utils import load_hide_follows diff --git a/daemon_get.py b/daemon_get.py index 4ae1ad76c..896e17450 100644 --- a/daemon_get.py +++ b/daemon_get.py @@ -93,7 +93,7 @@ from flags import is_corporate from flags import is_image_file from flags import is_artist from flags import is_blog_post -from utils import date_utcnow +from timeFunctions import date_utcnow from utils import replace_strings from utils import contains_invalid_chars from utils import save_json diff --git a/daemon_get_post.py b/daemon_get_post.py index 1e5c92b2a..223395e5c 100644 --- a/daemon_get_post.py +++ b/daemon_get_post.py @@ -13,11 +13,11 @@ from webapp_conversation import html_conversation_view from flags import is_public_post_from_url from flags import is_public_post from flags import is_premium_account +from flags import can_reply_to from utils import get_instance_url from utils import local_actor_url from utils import locate_post from utils import get_config_param -from utils import can_reply_to from utils import get_nickname_from_actor from utils import get_new_post_endpoints from utils import acct_dir diff --git a/daemon_post_confirm.py b/daemon_post_confirm.py index acaa03e2c..0a8172269 100644 --- a/daemon_post_confirm.py +++ b/daemon_post_confirm.py @@ -15,7 +15,7 @@ from utils import get_nickname_from_actor from utils import get_domain_from_actor from utils import get_full_domain from utils import local_actor_url -from utils import get_status_number +from status import get_status_number from follow import unfollow_account from follow import send_follow_request from follow import remove_follower diff --git a/daemon_post_newswire.py b/daemon_post_newswire.py index cebd36dfb..efb243ad8 100644 --- a/daemon_post_newswire.py +++ b/daemon_post_newswire.py @@ -16,12 +16,12 @@ from utils import data_dir from utils import remove_id_ending from utils import save_json from utils import first_paragraph_from_string -from utils import date_from_string_format from utils import load_json from utils import locate_post from utils import acct_dir from utils import get_instance_url from utils import get_nickname_from_actor +from timeFunctions import date_from_string_format from httpheaders import redirect_headers from posts import is_moderator from content import extract_text_fields_in_post diff --git a/daemon_post_profile.py b/daemon_post_profile.py index 9dc371ce0..d54cfa270 100644 --- a/daemon_post_profile.py +++ b/daemon_post_profile.py @@ -20,13 +20,13 @@ from httpheaders import clear_login_details from flags import is_artist from flags import is_memorial_account from flags import is_premium_account +from timeFunctions import get_account_timezone +from timeFunctions import set_account_timezone from utils import data_dir from utils import set_premium_account from utils import save_json from utils import save_reverse_timeline from utils import set_minimize_all_images -from utils import set_account_timezone -from utils import get_account_timezone from utils import set_memorials from utils import get_memorials from utils import license_link_from_name diff --git a/daemon_post_receive.py b/daemon_post_receive.py index 8be560d90..82c119679 100644 --- a/daemon_post_receive.py +++ b/daemon_post_receive.py @@ -31,8 +31,8 @@ from city import get_spoofed_city from flags import is_image_file from flags import is_float from searchable import set_searchable_by -from utils import date_utcnow -from utils import date_from_string_format +from timeFunctions import date_utcnow +from timeFunctions import date_from_string_format from utils import get_instance_url from utils import save_json from utils import remove_post_from_cache diff --git a/delete.py b/delete.py index c10b9a97e..2dfd3c63e 100644 --- a/delete.py +++ b/delete.py @@ -9,7 +9,6 @@ __module_group__ = "ActivityPub" import os from datetime import datetime, timezone -from utils import date_from_numbers from utils import has_object_string from utils import remove_domain_port from utils import has_users_path @@ -21,9 +20,10 @@ from utils import locate_post from utils import delete_post from utils import remove_moderation_post_from_index from utils import local_actor_url -from utils import date_utcnow -from utils import date_epoch from utils import get_actor_from_post +from timeFunctions import date_epoch +from timeFunctions import date_from_numbers +from timeFunctions import date_utcnow from session import post_json from webfinger import webfinger_handle from auth import create_basic_auth_header diff --git a/flags.py b/flags.py index 6a5c8ec17..326824fbe 100644 --- a/flags.py +++ b/flags.py @@ -9,9 +9,11 @@ __module_group__ = "Core" import os import re +from timeFunctions import date_utcnow +from timeFunctions import get_published_date +from timeFunctions import date_from_string_format +from timeFunctions import date_epoch from utils import acct_dir -from utils import date_utcnow -from utils import date_epoch from utils import data_dir from utils import get_config_param from utils import get_image_extensions @@ -23,7 +25,6 @@ from utils import has_object_dict from utils import locate_post from utils import load_json from utils import has_object_string_type -from utils import date_from_string_format from utils import get_reply_to from utils import text_in_file from utils import get_group_paths @@ -636,3 +637,46 @@ def is_corporate(server_name: str) -> bool: 'github' in server_lower: return True return False + + +def can_reply_to(base_dir: str, nickname: str, domain: str, + post_url: str, reply_interval_hours: int, + curr_date_str: str = None, + post_json_object: {} = None) -> bool: + """Is replying to the given local post permitted? + This is a spam mitigation feature, so that spammers can't + add a lot of replies to old post which you don't notice. + """ + if '/statuses/' not in post_url: + return True + if not post_json_object: + post_filename = locate_post(base_dir, nickname, domain, post_url) + if not post_filename: + # the post is not stored locally + return True + post_json_object = load_json(post_filename) + if not post_json_object: + return False + published = get_published_date(post_json_object) + if not published: + return False + + pub_date = date_from_string_format(published, ['%Y-%m-%dT%H:%M:%S%z']) + if not pub_date: + print('EX: can_reply_to unrecognized published date ' + str(published)) + return False + if not curr_date_str: + curr_date = date_utcnow() + else: + curr_date = \ + date_from_string_format(curr_date_str, ['%Y-%m-%dT%H:%M:%S%z']) + if not curr_date: + print('EX: can_reply_to unrecognized current date ' + + str(curr_date_str)) + return False + hours_since_publication = \ + int((curr_date - pub_date).total_seconds() / 3600) + if hours_since_publication < 0 or \ + hours_since_publication >= reply_interval_hours: + return False + return True diff --git a/follow.py b/follow.py index 20173c554..5129d0d31 100644 --- a/follow.py +++ b/follow.py @@ -21,10 +21,7 @@ from utils import valid_nickname from utils import domain_permitted from utils import get_domain_from_actor from utils import get_nickname_from_actor -from utils import get_status_number from utils import follow_person -from posts import send_signed_json -from posts import get_person_box from utils import load_json from utils import save_json from utils import is_account_dir @@ -34,6 +31,9 @@ from utils import text_in_file from utils import remove_eol from utils import get_actor_from_post from utils import data_dir +from status import get_status_number +from posts import send_signed_json +from posts import get_person_box from acceptreject import create_accept from acceptreject import create_reject from webfinger import webfinger_handle diff --git a/happening.py b/happening.py index 2f47f612e..23f972876 100644 --- a/happening.py +++ b/happening.py @@ -16,8 +16,6 @@ from flags import is_reminder from flags import is_public_post from utils import resembles_url from utils import replace_strings -from utils import date_from_numbers -from utils import date_from_string_format from utils import acct_handle_dir from utils import load_json from utils import save_json @@ -27,10 +25,12 @@ from utils import acct_dir from utils import remove_html from utils import get_display_name from utils import delete_post -from utils import get_status_number from utils import get_full_domain from utils import text_in_file from utils import remove_eol +from status import get_status_number +from timeFunctions import date_from_string_format +from timeFunctions import date_from_numbers from filters import is_filtered from context import get_individual_post_context from session import get_method diff --git a/httpsig.py b/httpsig.py index 05ac049fc..baaf7ef99 100644 --- a/httpsig.py +++ b/httpsig.py @@ -25,9 +25,9 @@ from utils import get_full_domain from utils import get_sha_256 from utils import get_sha_512 from utils import local_actor_url -from utils import date_utcnow -from utils import date_epoch -from utils import date_from_string_format +from timeFunctions import date_epoch +from timeFunctions import date_from_string_format +from timeFunctions import date_utcnow def message_content_digest(message_body_json_str: str, diff --git a/inbox.py b/inbox.py index 3066a9e87..682e3799c 100644 --- a/inbox.py +++ b/inbox.py @@ -14,6 +14,7 @@ import time import random from shutil import copyfile from linked_data_sig import verify_json_signature +from flags import can_reply_to from flags import is_system_account from flags import is_blog_post from flags import is_recent_post @@ -24,20 +25,19 @@ from flags import is_quote_toot from flags import url_permitted from quote import quote_toots_allowed from mitm import save_mitm_servers +from timeFunctions import date_utcnow +from timeFunctions import date_epoch +from timeFunctions import get_account_timezone from utils import harmless_markup from utils import lines_in_file -from utils import date_epoch -from utils import date_utcnow from utils import contains_statuses from utils import get_actor_from_post_id from utils import acct_handle_dir from utils import text_in_file from utils import get_media_descriptions_from_post from utils import get_summary_from_post -from utils import get_account_timezone from utils import domain_permitted from utils import get_reply_interval_hours -from utils import can_reply_to from utils import get_base_content_from_post from utils import acct_dir from utils import remove_domain_port @@ -49,7 +49,6 @@ from utils import has_users_path from utils import get_full_domain from utils import remove_id_ending from utils import create_inbox_queue_dir -from utils import get_status_number from utils import get_domain_from_actor from utils import get_nickname_from_actor from utils import locate_post @@ -63,6 +62,7 @@ from utils import get_actor_from_post from utils import data_dir from utils import is_dm from utils import has_actor +from status import get_status_number from httpsig import get_digest_algorithm_from_headers from httpsig import verify_post_headers from session import create_session diff --git a/inbox_receive.py b/inbox_receive.py index 4a733f062..b00f3cb92 100644 --- a/inbox_receive.py +++ b/inbox_receive.py @@ -13,6 +13,7 @@ from flags import is_recent_post from flags import is_quote_toot from status import actor_status_expired from quote import get_quote_toot_url +from timeFunctions import get_account_timezone from utils import get_actor_from_post_id from utils import contains_invalid_actor_url_chars from utils import get_attributed_to @@ -30,7 +31,6 @@ from utils import has_users_path from utils import has_object_string_type from utils import get_config_param from utils import acct_dir -from utils import get_account_timezone from utils import is_dm from utils import delete_cached_html from utils import harmless_markup diff --git a/inbox_receive_undo.py b/inbox_receive_undo.py index 4cb8018c4..34d5a8094 100644 --- a/inbox_receive_undo.py +++ b/inbox_receive_undo.py @@ -9,6 +9,7 @@ __module_group__ = "Timeline" import os from flags import has_group_type +from timeFunctions import get_account_timezone from utils import undo_announce_collection_entry from utils import has_object_dict from utils import remove_domain_port @@ -16,7 +17,6 @@ from utils import remove_id_ending from utils import get_url_from_post from utils import undo_reaction_collection_entry from utils import remove_html -from utils import get_account_timezone from utils import is_dm from utils import get_cached_post_filename from utils import load_json diff --git a/linked_data_sig.py b/linked_data_sig.py index 91eed7b84..f9e54651d 100644 --- a/linked_data_sig.py +++ b/linked_data_sig.py @@ -21,7 +21,7 @@ from cryptography.hazmat.primitives.asymmetric import utils as hazutils from pyjsonld import normalize from context import has_valid_context from utils import get_sha_256 -from utils import date_utcnow +from timeFunctions import date_utcnow def _options_hash(doc: {}) -> str: diff --git a/maps.py b/maps.py index 45f0188d3..8524f7721 100644 --- a/maps.py +++ b/maps.py @@ -19,9 +19,9 @@ from utils import save_json from utils import locate_post from utils import remove_html from utils import has_object_dict -from utils import date_utcnow -from utils import date_epoch -from utils import date_from_string_format +from timeFunctions import date_epoch +from timeFunctions import date_from_string_format +from timeFunctions import date_utcnow from session import get_resolved_url diff --git a/media.py b/media.py index 313f76f7e..f7230652c 100644 --- a/media.py +++ b/media.py @@ -15,8 +15,8 @@ import random from random import randint from hashlib import sha1 from auth import create_password -from utils import date_epoch -from utils import date_utcnow +from timeFunctions import date_utcnow +from timeFunctions import date_epoch from utils import safe_system_string from utils import get_base_content_from_post from utils import get_full_domain diff --git a/newsdaemon.py b/newsdaemon.py index 042ded59d..470fe481b 100644 --- a/newsdaemon.py +++ b/newsdaemon.py @@ -23,19 +23,19 @@ from newswire import get_dict_from_newswire # from posts import send_signed_json from posts import create_news_post from posts import archive_posts_for_person -from utils import date_from_string_format -from utils import date_utcnow +from timeFunctions import date_from_string_format +from timeFunctions import date_utcnow from utils import valid_hash_tag from utils import get_base_content_from_post from utils import remove_html from utils import get_full_domain from utils import load_json from utils import save_json -from utils import get_status_number from utils import dangerous_markup from utils import local_actor_url from utils import text_in_file from utils import data_dir +from status import get_status_number from session import create_session from threads import begin_thread from webapp_hashtagswarm import store_hash_tags diff --git a/newswire.py b/newswire.py index c32287bc9..3518e5b16 100644 --- a/newswire.py +++ b/newswire.py @@ -17,7 +17,7 @@ import errno from datetime import timedelta from datetime import timezone from collections import OrderedDict -from utils import valid_post_date +from timeFunctions import valid_post_date from categories import set_hashtag_category from flags import is_suspended from flags import is_local_network_address @@ -28,7 +28,6 @@ from utils import image_mime_types_dict from utils import resembles_url from utils import get_url_from_post from utils import remove_zero_length_strings -from utils import date_from_string_format from utils import acct_handle_dir from utils import remove_eol from utils import get_domain_from_actor @@ -48,6 +47,7 @@ from utils import acct_dir from utils import local_actor_url from utils import escape_text from utils import unescaped_text +from timeFunctions import date_from_string_format from blocking import is_blocked_domain from blocking import is_blocked_hashtag from filters import is_filtered diff --git a/outbox.py b/outbox.py index 1e8e15c86..7a3be1456 100644 --- a/outbox.py +++ b/outbox.py @@ -18,12 +18,12 @@ from posts import send_to_named_addresses_thread from flags import is_featured_writer from flags import is_quote_toot from quote import quote_toots_allowed +from timeFunctions import get_account_timezone from utils import data_dir from utils import get_post_attachments from utils import get_attributed_to from utils import contains_invalid_actor_url_chars from utils import get_attachment_property_value -from utils import get_account_timezone from utils import has_object_string_type from utils import get_base_content_from_post from utils import has_object_dict diff --git a/person.py b/person.py index d0a00d518..ddae7520c 100644 --- a/person.py +++ b/person.py @@ -38,12 +38,12 @@ from roles import actor_roles_from_list from roles import get_actor_roles_list from media import process_meta_data from flags import is_image_file +from timeFunctions import date_utcnow from utils import get_person_icon from utils import account_is_indexable from utils import get_image_mime_type from utils import get_instance_url from utils import get_url_from_post -from utils import date_utcnow from utils import get_memorials from utils import is_account_dir from utils import valid_hash_tag @@ -57,7 +57,6 @@ from utils import contains_invalid_actor_url_chars from utils import replace_users_with_at from utils import remove_eol from utils import remove_domain_port -from utils import get_status_number from utils import get_full_domain from utils import valid_nickname from utils import load_json @@ -77,6 +76,7 @@ from utils import text_in_file from utils import contains_statuses from utils import get_actor_from_post from utils import data_dir +from status import get_status_number from session import get_json_valid from session import create_session from session import get_json diff --git a/pgp.py b/pgp.py index 7a392a31e..9dfdb13c1 100644 --- a/pgp.py +++ b/pgp.py @@ -18,10 +18,10 @@ from utils import get_occupation_skills from utils import get_url_from_post from utils import safe_system_string from utils import get_full_domain -from utils import get_status_number from utils import local_actor_url from utils import replace_users_with_at from utils import remove_html +from status import get_status_number from webfinger import webfinger_handle from posts import get_person_box from auth import create_basic_auth_header diff --git a/posts.py b/posts.py index 9d659cadb..64c6691f4 100644 --- a/posts.py +++ b/posts.py @@ -41,6 +41,10 @@ from flags import contains_private_key from flags import has_group_type from flags import is_premium_account from flags import url_permitted +from timeFunctions import date_utcnow +from timeFunctions import date_from_string_format +from timeFunctions import date_epoch +from timeFunctions import valid_post_date from utils import resembles_url from utils import get_person_icon from utils import remove_post_from_index @@ -50,9 +54,6 @@ from utils import get_actor_from_post_id from utils import string_contains from utils import get_post_attachments from utils import get_url_from_post -from utils import date_from_string_format -from utils import date_epoch -from utils import date_utcnow from utils import get_attributed_to from utils import contains_statuses from utils import contains_invalid_actor_url_chars @@ -76,10 +77,8 @@ from utils import reject_post_id from utils import remove_invalid_chars from utils import file_last_modified from utils import has_users_path -from utils import valid_post_date from utils import get_full_domain from utils import get_followers_list -from utils import get_status_number from utils import create_person_dir from utils import get_nickname_from_actor from utils import get_domain_from_actor @@ -90,7 +89,6 @@ from utils import load_json from utils import save_json from utils import get_config_param from utils import locate_news_votes -from utils import locate_news_arrival from utils import votes_on_newswire_item from utils import remove_html from utils import dangerous_markup @@ -99,6 +97,7 @@ from utils import local_actor_url from utils import get_reply_to from utils import get_actor_from_post from utils import data_dir +from status import get_status_number from media import get_music_metadata from media import attach_media from media import replace_you_tube @@ -4840,6 +4839,39 @@ def remove_post_interactions(post_json_object: {}, force: bool) -> bool: return True +def _locate_news_arrival(base_dir: str, domain: str, + post_url: str) -> str: + """Returns the arrival time for a news post + within the news user account + """ + post_url1 = post_url.strip() + post_url = remove_eol(post_url1) + + # if this post in the shared inbox? + post_url = remove_id_ending(post_url.strip()).replace('/', '#') + + if post_url.endswith('.json'): + post_url = post_url + '.arrived' + else: + post_url = post_url + '.json.arrived' + + account_dir = data_dir(base_dir) + '/news@' + domain + '/' + post_filename = account_dir + 'outbox/' + post_url + if os.path.isfile(post_filename): + try: + with open(post_filename, 'r', encoding='utf-8') as fp_arrival: + arrival = fp_arrival.read() + if arrival: + arrival_date = \ + date_from_string_format(arrival, + ["%Y-%m-%dT%H:%M:%S%z"]) + return arrival_date + except OSError: + print('EX: _locate_news_arrival unable to read ' + post_filename) + + return None + + def _passed_newswire_voting(newswire_votes_threshold: int, base_dir: str, domain: str, post_filename: str, @@ -4853,7 +4885,7 @@ def _passed_newswire_voting(newswire_votes_threshold: int, # note that the presence of an arrival file also indicates # that this post is moderated arrival_date = \ - locate_news_arrival(base_dir, domain, post_filename) + _locate_news_arrival(base_dir, domain, post_filename) if not arrival_date: return True # how long has elapsed since this post arrived? diff --git a/reading.py b/reading.py index d48b4adbc..36283bafc 100644 --- a/reading.py +++ b/reading.py @@ -20,8 +20,8 @@ from utils import load_json from utils import save_json from utils import remove_html from utils import get_image_extensions -from utils import date_epoch -from utils import date_from_string_format +from timeFunctions import date_epoch +from timeFunctions import date_from_string_format def get_book_link_from_content(content: str) -> str: diff --git a/roles.py b/roles.py index 75ae900c6..2f9e8fbbc 100644 --- a/roles.py +++ b/roles.py @@ -11,11 +11,11 @@ import os from utils import data_dir from utils import load_json from utils import save_json -from utils import get_status_number from utils import remove_domain_port from utils import acct_dir from utils import text_in_file from utils import get_config_param +from status import get_status_number def _clear_role_status(base_dir: str, role: str) -> None: diff --git a/schedule.py b/schedule.py index 9641e9b18..ee5fce140 100644 --- a/schedule.py +++ b/schedule.py @@ -10,16 +10,16 @@ __module_group__ = "Calendar" import os import time from utils import data_dir -from utils import date_from_string_format -from utils import date_epoch +from timeFunctions import date_from_string_format +from timeFunctions import date_epoch from utils import acct_handle_dir from utils import has_object_dict -from utils import get_status_number from utils import load_json from utils import is_account_dir from utils import acct_dir from utils import remove_eol -from utils import date_utcnow +from status import get_status_number +from timeFunctions import date_utcnow from outbox import post_message_to_outbox from session import create_session from threads import begin_thread diff --git a/shares.py b/shares.py index db3aab060..3abd181b6 100644 --- a/shares.py +++ b/shares.py @@ -24,18 +24,18 @@ from session import post_image from session import create_session from session import get_json_valid from flags import is_float +from timeFunctions import date_utcnow +from timeFunctions import date_string_to_seconds +from timeFunctions import date_seconds_to_string from utils import replace_strings from utils import data_dir from utils import resembles_url -from utils import date_utcnow from utils import dangerous_markup from utils import remove_html from utils import get_media_extensions from utils import acct_handle_dir from utils import remove_eol from utils import has_object_string_type -from utils import date_string_to_seconds -from utils import date_seconds_to_string from utils import get_config_param from utils import get_full_domain from utils import valid_nickname diff --git a/status.py b/status.py index e7ba4c27c..bbbcf9f62 100644 --- a/status.py +++ b/status.py @@ -9,8 +9,9 @@ __module_group__ = "Core" __accounts_data_path__ = None __accounts_data_path_tests__ = False -from utils import date_utcnow -from utils import date_from_string_format +from timeFunctions import date_utcnow +from timeFunctions import date_from_string_format +from timeFunctions import date_epoch from utils import remove_html from unicodetext import standardize_text @@ -66,3 +67,29 @@ def actor_status_expired(actor_status_json: {}) -> bool: if status_end_time < curr_time: return True return False + + +def get_status_number(published_str: str = None) -> (str, str): + """Returns the status number and published date + """ + if not published_str: + curr_time = date_utcnow() + else: + curr_time = \ + date_from_string_format(published_str, ['%Y-%m-%dT%H:%M:%S%z']) + days_since_epoch = (curr_time - date_epoch()).days + # status is the number of seconds since epoch + status_number = \ + str(((days_since_epoch * 24 * 60 * 60) + + (curr_time.hour * 60 * 60) + + (curr_time.minute * 60) + + curr_time.second) * 1000 + + int(curr_time.microsecond / 1000)) + # See https://github.com/tootsuite/mastodon/blob/ + # 995f8b389a66ab76ec92d9a240de376f1fc13a38/lib/mastodon/snowflake.rb + # use the leftover microseconds as the sequence number + sequence_id = curr_time.microsecond % 1000 + # shift by 16bits "sequence data" + status_number = str((int(status_number) << 16) + sequence_id) + published = curr_time.strftime("%Y-%m-%dT%H:%M:%SZ") + return status_number, published diff --git a/tests.py b/tests.py index 057691720..b3d985489 100644 --- a/tests.py +++ b/tests.py @@ -59,6 +59,7 @@ from follow import send_follow_request_via_server from follow import send_unfollow_request_via_server from siteactive import site_is_active from siteactive import is_online +from flags import can_reply_to from flags import contains_pgp_public_key from flags import is_group_actor from flags import is_group_account @@ -72,27 +73,26 @@ from utils import data_dir from utils import data_dir_testing from utils import remove_link_tracking from utils import get_url_from_post -from utils import date_from_string_format -from utils import date_utcnow from utils import remove_markup_tag from utils import remove_style_within_html from utils import html_tag_has_closing from unicodetext import remove_inverted_text from unicodetext import remove_square_capitals from unicodetext import standardize_text +from timeFunctions import date_from_string_format +from timeFunctions import date_utcnow +from timeFunctions import convert_published_to_local_timezone +from timeFunctions import date_string_to_seconds +from timeFunctions import date_seconds_to_string from utils import remove_eol from utils import text_in_file -from utils import convert_published_to_local_timezone from utils import convert_to_snake_case from utils import get_sha_256 from utils import dangerous_svg -from utils import can_reply_to from utils import get_actor_languages_list from utils import get_category_types from utils import get_supported_languages from utils import set_config_param -from utils import date_string_to_seconds -from utils import date_seconds_to_string from utils import valid_password from utils import user_agent_domain from utils import camel_case_split @@ -107,12 +107,12 @@ from utils import get_domain_from_actor from utils import copytree from utils import load_json from utils import save_json -from utils import get_status_number from utils import valid_hash_tag from utils import get_followers_of_person from utils import remove_html from utils import dangerous_markup from utils import acct_dir +from status import get_status_number from pgp import extract_pgp_public_key from pgp import pgp_public_key_upload from follow import add_follower_of_person diff --git a/threads.py b/threads.py index afaab880c..e35f6a3cf 100644 --- a/threads.py +++ b/threads.py @@ -11,7 +11,7 @@ import threading import sys import time from socket import error as SocketError -from utils import date_utcnow +from timeFunctions import date_utcnow class thread_with_trace(threading.Thread): diff --git a/timeFunctions.py b/timeFunctions.py new file mode 100644 index 000000000..c8a41fd85 --- /dev/null +++ b/timeFunctions.py @@ -0,0 +1,242 @@ +__filename__ = "timeFunctions.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.6.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@libreserver.org" +__status__ = "Production" +__module_group__ = "Core" + +import os +import time +import datetime +from dateutil.tz import tz +from utils import acct_dir +from utils import data_dir +from utils import has_object_dict + + +def convert_published_to_local_timezone(published, timezone: str) -> str: + """Converts a post published time into local time + """ + to_zone = None + from_zone = tz.gettz('UTC') + if timezone: + try: + to_zone = tz.gettz(timezone) + except BaseException: + pass + if not timezone or not to_zone: + return published + + utc = published.replace(tzinfo=from_zone) + local_time = utc.astimezone(to_zone) + return local_time + + +def _utc_mktime(utc_tuple): + """Returns number of seconds elapsed since epoch + Note that no timezone are taken into consideration. + utc tuple must be: (year, month, day, hour, minute, second) + """ + + if len(utc_tuple) == 6: + utc_tuple += (0, 0, 0) + return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0)) + + +def _datetime_to_timestamp(dtime): + """Converts a datetime object to UTC timestamp""" + return int(_utc_mktime(dtime.timetuple())) + + +def date_utcnow(): + """returns the time now + """ + return datetime.datetime.now(datetime.timezone.utc) + + +def date_from_numbers(year: int, month: int, day: int, + hour: int, mins: int): + """returns an offset-aware datetime + """ + return datetime.datetime(year, month, day, hour, mins, 0, + tzinfo=datetime.timezone.utc) + + +def date_from_string_format(date_str: str, formats: []): + """returns an offset-aware datetime from a string date + """ + if not formats: + formats = ("%a, %d %b %Y %H:%M:%S %Z", + "%a, %d %b %Y %H:%M:%S %z", + "%Y-%m-%dT%H:%M:%S%z") + dtime = None + for date_format in formats: + try: + dtime = \ + datetime.datetime.strptime(date_str, date_format) + except BaseException: + continue + break + if not dtime: + return None + if not dtime.tzinfo: + dtime = dtime.replace(tzinfo=datetime.timezone.utc) + return dtime + + +def date_epoch(): + """returns an offset-aware version of epoch + """ + return date_from_numbers(1970, 1, 1, 0, 0) + + +def date_string_to_seconds(date_str: str) -> int: + """Converts a date string (eg "published") into seconds since epoch + """ + expiry_time = \ + date_from_string_format(date_str, ['%Y-%m-%dT%H:%M:%S%z']) + if not expiry_time: + print('EX: date_string_to_seconds unable to parse date ' + + str(date_str)) + return None + return _datetime_to_timestamp(expiry_time) + + +def date_seconds_to_string(date_sec: int) -> str: + """Converts a date in seconds since epoch to a string + """ + this_date = \ + datetime.datetime.fromtimestamp(date_sec, datetime.timezone.utc) + if not this_date.tzinfo: + this_date = this_date.replace(tzinfo=datetime.timezone.utc) + this_date_tz = this_date.astimezone(datetime.timezone.utc) + return this_date_tz.strftime("%Y-%m-%dT%H:%M:%SZ") + + +def get_account_timezone(base_dir: str, nickname: str, domain: str) -> str: + """Returns the timezone for the given account + """ + tz_filename = \ + acct_dir(base_dir, nickname, domain) + '/timezone.txt' + if not os.path.isfile(tz_filename): + return None + timezone = None + try: + with open(tz_filename, 'r', encoding='utf-8') as fp_timezone: + timezone = fp_timezone.read().strip() + except OSError: + print('EX: get_account_timezone unable to read ' + tz_filename) + return timezone + + +def set_account_timezone(base_dir: str, nickname: str, domain: str, + timezone: str) -> None: + """Sets the timezone for the given account + """ + tz_filename = \ + acct_dir(base_dir, nickname, domain) + '/timezone.txt' + timezone = timezone.strip() + try: + with open(tz_filename, 'w+', encoding='utf-8') as fp_timezone: + fp_timezone.write(timezone) + except OSError: + print('EX: set_account_timezone unable to write ' + + tz_filename) + + +def load_account_timezones(base_dir: str) -> {}: + """Returns a dictionary containing the preferred timezone for each account + """ + account_timezone = {} + dir_str = data_dir(base_dir) + for _, dirs, _ in os.walk(dir_str): + for acct in dirs: + if '@' not in acct: + continue + if acct.startswith('inbox@') or acct.startswith('Actor@'): + continue + acct_directory = os.path.join(dir_str, acct) + tz_filename = acct_directory + '/timezone.txt' + if not os.path.isfile(tz_filename): + continue + timezone = None + try: + with open(tz_filename, 'r', encoding='utf-8') as fp_timezone: + timezone = fp_timezone.read().strip() + except OSError: + print('EX: load_account_timezones unable to read ' + + tz_filename) + if timezone: + nickname = acct.split('@')[0] + account_timezone[nickname] = timezone + break + return account_timezone + + +def week_day_of_month_start(month_number: int, year: int) -> int: + """Gets the day number of the first day of the month + 1=sun, 7=sat + """ + first_day_of_month = date_from_numbers(year, month_number, 1, 0, 0) + return int(first_day_of_month.strftime("%w")) + 1 + + +def valid_post_date(published: str, max_age_days: int, debug: bool) -> bool: + """Returns true if the published date is recent and is not in the future + """ + baseline_time = date_epoch() + + days_diff = date_utcnow() - baseline_time + now_days_since_epoch = days_diff.days + + post_time_object = \ + date_from_string_format(published, ["%Y-%m-%dT%H:%M:%S%z"]) + if not post_time_object: + if debug: + print('EX: valid_post_date invalid published date ' + + str(published)) + return False + + days_diff = post_time_object - baseline_time + post_days_since_epoch = days_diff.days + + if post_days_since_epoch > now_days_since_epoch: + if debug: + print("Inbox post has a published date in the future!") + return False + + if now_days_since_epoch - post_days_since_epoch >= max_age_days: + if debug: + print("Inbox post is not recent enough") + return False + return True + + +def time_days_ago(datestr: str) -> int: + """returns the number of days ago for the given date + """ + date1 = \ + date_from_string_format(datestr, + ["%Y-%m-%dT%H:%M:%S%z"]) + if not date1: + return 0 + date_diff = date_utcnow() - date1 + return date_diff.days + + +def get_published_date(post_json_object: {}) -> str: + """Returns the published date on the given post + """ + published = None + if post_json_object.get('published'): + published = post_json_object['published'] + elif has_object_dict(post_json_object): + if post_json_object['object'].get('published'): + published = post_json_object['object']['published'] + if not published: + return None + if not isinstance(published, str): + return None + return published diff --git a/utils.py b/utils.py index a74b807c3..23b5ec4fb 100644 --- a/utils.py +++ b/utils.py @@ -18,7 +18,6 @@ import json import locale from pprint import pprint import idna -from dateutil.tz import tz from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from followingCalendar import add_person_to_calendar @@ -65,64 +64,6 @@ def remove_zero_length_strings(text: str) -> str: return text.replace('​', '') -def _utc_mktime(utc_tuple): - """Returns number of seconds elapsed since epoch - Note that no timezone are taken into consideration. - utc tuple must be: (year, month, day, hour, minute, second) - """ - - if len(utc_tuple) == 6: - utc_tuple += (0, 0, 0) - return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0)) - - -def _datetime_to_timestamp(dtime): - """Converts a datetime object to UTC timestamp""" - return int(_utc_mktime(dtime.timetuple())) - - -def date_utcnow(): - """returns the time now - """ - return datetime.datetime.now(datetime.timezone.utc) - - -def date_from_numbers(year: int, month: int, day: int, - hour: int, mins: int): - """returns an offset-aware datetime - """ - return datetime.datetime(year, month, day, hour, mins, 0, - tzinfo=datetime.timezone.utc) - - -def date_from_string_format(date_str: str, formats: []): - """returns an offset-aware datetime from a string date - """ - if not formats: - formats = ("%a, %d %b %Y %H:%M:%S %Z", - "%a, %d %b %Y %H:%M:%S %z", - "%Y-%m-%dT%H:%M:%S%z") - dtime = None - for date_format in formats: - try: - dtime = \ - datetime.datetime.strptime(date_str, date_format) - except BaseException: - continue - break - if not dtime: - return None - if not dtime.tzinfo: - dtime = dtime.replace(tzinfo=datetime.timezone.utc) - return dtime - - -def date_epoch(): - """returns an offset-aware version of epoch - """ - return date_from_numbers(1970, 1, 1, 0, 0) - - def get_url_from_post(url_field) -> str: """Returns a url from a post object """ @@ -658,37 +599,6 @@ def has_users_path(path_str: str) -> bool: return False -def valid_post_date(published: str, max_age_days: int, debug: bool) -> bool: - """Returns true if the published date is recent and is not in the future - """ - baseline_time = date_epoch() - - days_diff = date_utcnow() - baseline_time - now_days_since_epoch = days_diff.days - - post_time_object = \ - date_from_string_format(published, ["%Y-%m-%dT%H:%M:%S%z"]) - if not post_time_object: - if debug: - print('EX: valid_post_date invalid published date ' + - str(published)) - return False - - days_diff = post_time_object - baseline_time - post_days_since_epoch = days_diff.days - - if post_days_since_epoch > now_days_since_epoch: - if debug: - print("Inbox post has a published date in the future!") - return False - - if now_days_since_epoch - post_days_since_epoch >= max_age_days: - if debug: - print("Inbox post is not recent enough") - return False - return True - - def get_full_domain(domain: str, port: int) -> str: """Returns the full domain name, including port number """ @@ -1147,32 +1057,6 @@ def load_json_onionify(filename: str, domain: str, onion_domain: str, return json_object -def get_status_number(published_str: str = None) -> (str, str): - """Returns the status number and published date - """ - if not published_str: - curr_time = date_utcnow() - else: - curr_time = \ - date_from_string_format(published_str, ['%Y-%m-%dT%H:%M:%S%z']) - days_since_epoch = (curr_time - date_epoch()).days - # status is the number of seconds since epoch - status_number = \ - str(((days_since_epoch * 24 * 60 * 60) + - (curr_time.hour * 60 * 60) + - (curr_time.minute * 60) + - curr_time.second) * 1000 + - int(curr_time.microsecond / 1000)) - # See https://github.com/tootsuite/mastodon/blob/ - # 995f8b389a66ab76ec92d9a240de376f1fc13a38/lib/mastodon/snowflake.rb - # use the leftover microseconds as the sequence number - sequence_id = curr_time.microsecond % 1000 - # shift by 16bits "sequence data" - status_number = str((int(status_number) << 16) + sequence_id) - published = curr_time.strftime("%Y-%m-%dT%H:%M:%SZ") - return status_number, published - - def evil_incarnate() -> []: """Hardcoded blocked domains """ @@ -1866,39 +1750,6 @@ def locate_news_votes(base_dir: str, domain: str, return None -def locate_news_arrival(base_dir: str, domain: str, - post_url: str) -> str: - """Returns the arrival time for a news post - within the news user account - """ - post_url1 = post_url.strip() - post_url = remove_eol(post_url1) - - # if this post in the shared inbox? - post_url = remove_id_ending(post_url.strip()).replace('/', '#') - - if post_url.endswith('.json'): - post_url = post_url + '.arrived' - else: - post_url = post_url + '.json.arrived' - - account_dir = data_dir(base_dir) + '/news@' + domain + '/' - post_filename = account_dir + 'outbox/' + post_url - if os.path.isfile(post_filename): - try: - with open(post_filename, 'r', encoding='utf-8') as fp_arrival: - arrival = fp_arrival.read() - if arrival: - arrival_date = \ - date_from_string_format(arrival, - ["%Y-%m-%dT%H:%M:%S%z"]) - return arrival_date - except OSError: - print('EX: locate_news_arrival unable to read ' + post_filename) - - return None - - def locate_post(base_dir: str, nickname: str, domain: str, post_url: str, replies: bool = False) -> str: """Returns the filename for the given status post url @@ -1937,22 +1788,6 @@ def locate_post(base_dir: str, nickname: str, domain: str, return None -def _get_published_date(post_json_object: {}) -> str: - """Returns the published date on the given post - """ - published = None - if post_json_object.get('published'): - published = post_json_object['published'] - elif has_object_dict(post_json_object): - if post_json_object['object'].get('published'): - published = post_json_object['object']['published'] - if not published: - return None - if not isinstance(published, str): - return None - return published - - def get_reply_interval_hours(base_dir: str, nickname: str, domain: str, default_reply_interval_hrs: int) -> int: """Returns the reply interval for the given account. @@ -1994,49 +1829,6 @@ def set_reply_interval_hours(base_dir: str, nickname: str, domain: str, return False -def can_reply_to(base_dir: str, nickname: str, domain: str, - post_url: str, reply_interval_hours: int, - curr_date_str: str = None, - post_json_object: {} = None) -> bool: - """Is replying to the given local post permitted? - This is a spam mitigation feature, so that spammers can't - add a lot of replies to old post which you don't notice. - """ - if '/statuses/' not in post_url: - return True - if not post_json_object: - post_filename = locate_post(base_dir, nickname, domain, post_url) - if not post_filename: - # the post is not stored locally - return True - post_json_object = load_json(post_filename) - if not post_json_object: - return False - published = _get_published_date(post_json_object) - if not published: - return False - - pub_date = date_from_string_format(published, ['%Y-%m-%dT%H:%M:%S%z']) - if not pub_date: - print('EX: can_reply_to unrecognized published date ' + str(published)) - return False - if not curr_date_str: - curr_date = date_utcnow() - else: - curr_date = \ - date_from_string_format(curr_date_str, ['%Y-%m-%dT%H:%M:%S%z']) - if not curr_date: - print('EX: can_reply_to unrecognized current date ' + - str(curr_date_str)) - return False - hours_since_publication = \ - int((curr_date - pub_date).total_seconds() / 3600) - if hours_since_publication < 0 or \ - hours_since_publication >= reply_interval_hours: - return False - return True - - def _remove_attachment(base_dir: str, http_prefix: str, nickname: str, domain: str, post_json: {}) -> None: """Removes media files for an attachment @@ -3106,14 +2898,6 @@ def update_announce_collection(recent_posts_cache: {}, save_json(post_json_object, post_filename) -def week_day_of_month_start(month_number: int, year: int) -> int: - """Gets the day number of the first day of the month - 1=sun, 7=sat - """ - first_day_of_month = date_from_numbers(year, month_number, 1, 0, 0) - return int(first_day_of_month.strftime("%w")) + 1 - - def media_file_mime_type(filename: str) -> str: """Given a media filename return its mime type """ @@ -3149,18 +2933,6 @@ def media_file_mime_type(filename: str) -> str: return extensions[file_ext] -def time_days_ago(datestr: str) -> int: - """returns the number of days ago for the given date - """ - date1 = \ - date_from_string_format(datestr, - ["%Y-%m-%dT%H:%M:%S%z"]) - if not date1: - return 0 - date_diff = date_utcnow() - date1 - return date_diff.days - - def camel_case_split(text: str) -> str: """ Splits CamelCase into "Camel Case" """ @@ -3526,29 +3298,6 @@ def valid_password(password: str, debug: bool) -> bool: return True -def date_string_to_seconds(date_str: str) -> int: - """Converts a date string (eg "published") into seconds since epoch - """ - expiry_time = \ - date_from_string_format(date_str, ['%Y-%m-%dT%H:%M:%S%z']) - if not expiry_time: - print('EX: date_string_to_seconds unable to parse date ' + - str(date_str)) - return None - return _datetime_to_timestamp(expiry_time) - - -def date_seconds_to_string(date_sec: int) -> str: - """Converts a date in seconds since epoch to a string - """ - this_date = \ - datetime.datetime.fromtimestamp(date_sec, datetime.timezone.utc) - if not this_date.tzinfo: - this_date = this_date.replace(tzinfo=datetime.timezone.utc) - this_date_tz = this_date.astimezone(datetime.timezone.utc) - return this_date_tz.strftime("%Y-%m-%dT%H:%M:%SZ") - - def get_currencies() -> {}: """Returns a dictionary of currencies """ @@ -3796,53 +3545,6 @@ def valid_hash_tag(hashtag: str) -> bool: return False -def convert_published_to_local_timezone(published, timezone: str) -> str: - """Converts a post published time into local time - """ - to_zone = None - from_zone = tz.gettz('UTC') - if timezone: - try: - to_zone = tz.gettz(timezone) - except BaseException: - pass - if not timezone or not to_zone: - return published - - utc = published.replace(tzinfo=from_zone) - local_time = utc.astimezone(to_zone) - return local_time - - -def load_account_timezones(base_dir: str) -> {}: - """Returns a dictionary containing the preferred timezone for each account - """ - account_timezone = {} - dir_str = data_dir(base_dir) - for _, dirs, _ in os.walk(dir_str): - for acct in dirs: - if '@' not in acct: - continue - if acct.startswith('inbox@') or acct.startswith('Actor@'): - continue - acct_directory = os.path.join(dir_str, acct) - tz_filename = acct_directory + '/timezone.txt' - if not os.path.isfile(tz_filename): - continue - timezone = None - try: - with open(tz_filename, 'r', encoding='utf-8') as fp_timezone: - timezone = fp_timezone.read().strip() - except OSError: - print('EX: load_account_timezones unable to read ' + - tz_filename) - if timezone: - nickname = acct.split('@')[0] - account_timezone[nickname] = timezone - break - return account_timezone - - def load_bold_reading(base_dir: str) -> {}: """Returns a dictionary containing the bold reading status for each account """ @@ -3902,37 +3604,6 @@ def load_hide_recent_posts(base_dir: str) -> {}: return hide_recent_posts -def get_account_timezone(base_dir: str, nickname: str, domain: str) -> str: - """Returns the timezone for the given account - """ - tz_filename = \ - acct_dir(base_dir, nickname, domain) + '/timezone.txt' - if not os.path.isfile(tz_filename): - return None - timezone = None - try: - with open(tz_filename, 'r', encoding='utf-8') as fp_timezone: - timezone = fp_timezone.read().strip() - except OSError: - print('EX: get_account_timezone unable to read ' + tz_filename) - return timezone - - -def set_account_timezone(base_dir: str, nickname: str, domain: str, - timezone: str) -> None: - """Sets the timezone for the given account - """ - tz_filename = \ - acct_dir(base_dir, nickname, domain) + '/timezone.txt' - timezone = timezone.strip() - try: - with open(tz_filename, 'w+', encoding='utf-8') as fp_timezone: - fp_timezone.write(timezone) - except OSError: - print('EX: set_account_timezone unable to write ' + - tz_filename) - - def _is_onion_request(calling_domain: str, referer_domain: str, domain: str, onion_domain: str) -> bool: """Do the given domains indicate that this is a request diff --git a/webapp_calendar.py b/webapp_calendar.py index 2f8a48b47..05057405c 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -18,14 +18,14 @@ from utils import get_nickname_from_actor from utils import get_domain_from_actor from utils import locate_post from utils import load_json -from utils import week_day_of_month_start from utils import get_alt_path from utils import remove_domain_port from utils import acct_dir from utils import local_actor_url from utils import replace_users_with_at from utils import language_right_to_left -from utils import date_from_string_format +from timeFunctions import week_day_of_month_start +from timeFunctions import date_from_string_format from happening import get_todays_events from happening import get_calendar_events from happening import get_todays_events_icalendar diff --git a/webapp_column_right.py b/webapp_column_right.py index ec0e1b959..9a6d6c708 100644 --- a/webapp_column_right.py +++ b/webapp_column_right.py @@ -24,7 +24,7 @@ from utils import get_nickname_from_actor from utils import get_config_param from utils import remove_domain_port from utils import acct_dir -from utils import date_from_string_format +from timeFunctions import date_from_string_format from posts import is_moderator from newswire import get_newswire_favicon_url from webapp_utils import get_right_image_file diff --git a/webapp_confirm.py b/webapp_confirm.py index 7516c1019..96cad6310 100644 --- a/webapp_confirm.py +++ b/webapp_confirm.py @@ -18,7 +18,7 @@ from utils import load_json from utils import get_config_param from utils import get_alt_path from utils import acct_dir -from utils import get_account_timezone +from timeFunctions import get_account_timezone from blocking import sending_is_blocked2 from webapp_utils import set_custom_background from webapp_utils import html_header_with_external_style diff --git a/webapp_create_post.py b/webapp_create_post.py index d3384d295..5b9617a30 100644 --- a/webapp_create_post.py +++ b/webapp_create_post.py @@ -26,10 +26,10 @@ from utils import get_config_param from utils import acct_dir from utils import get_currencies from utils import get_category_types -from utils import get_account_timezone from utils import get_supported_languages from utils import get_attributed_to from utils import get_full_domain +from timeFunctions import get_account_timezone from blocking import sending_is_blocked2 from webapp_utils import open_content_warning from webapp_utils import edit_check_box diff --git a/webapp_frontscreen.py b/webapp_frontscreen.py index 1d6040acc..7c06577d6 100644 --- a/webapp_frontscreen.py +++ b/webapp_frontscreen.py @@ -11,7 +11,7 @@ import os from flags import is_system_account from utils import get_domain_from_actor from utils import get_config_param -from utils import get_account_timezone +from timeFunctions import get_account_timezone from person import person_box_json from webapp_utils import html_header_with_external_style from webapp_utils import html_footer diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py index b3b8b4340..a50873ff9 100644 --- a/webapp_hashtagswarm.py +++ b/webapp_hashtagswarm.py @@ -10,20 +10,20 @@ __module_group__ = "Web Interface" import os from datetime import datetime, timezone from flags import is_public_post +from timeFunctions import date_utcnow +from timeFunctions import date_from_string_format +from timeFunctions import date_epoch from utils import valid_hash_tag from utils import remove_id_ending from utils import resembles_url from utils import has_object_dict from utils import local_actor_url -from utils import date_from_string_format from utils import file_last_modified from utils import acct_dir from utils import data_dir from utils import get_nickname_from_actor from utils import get_config_param from utils import escape_text -from utils import date_utcnow -from utils import date_epoch from utils import string_contains from delete import remove_old_hashtags from maps import get_category_from_post diff --git a/webapp_likers.py b/webapp_likers.py index a877972e0..35d9f5574 100644 --- a/webapp_likers.py +++ b/webapp_likers.py @@ -10,12 +10,12 @@ __module_group__ = "ActivityPub" import os from utils import locate_post from utils import get_config_param -from utils import get_account_timezone from utils import get_display_name from utils import get_nickname_from_actor from utils import has_object_dict from utils import load_json from utils import get_actor_from_post +from timeFunctions import get_account_timezone from person import get_person_avatar_url from webapp_utils import html_header_with_external_style from webapp_utils import html_footer diff --git a/webapp_post.py b/webapp_post.py index c0709c6a6..f319f9ee4 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -45,7 +45,6 @@ from utils import contains_statuses from utils import data_dir from utils import get_post_attachments from utils import get_url_from_post -from utils import date_from_string_format from utils import remove_markup_tag from utils import ap_proxy_type from utils import remove_style_within_html @@ -54,7 +53,8 @@ from utils import dont_speak_hashtags from utils import remove_eol from utils import disallow_announce from utils import disallow_reply -from utils import convert_published_to_local_timezone +from timeFunctions import date_from_string_format +from timeFunctions import convert_published_to_local_timezone from utils import remove_hash_from_post_id from utils import remove_html from utils import get_actor_languages_list diff --git a/webapp_profile.py b/webapp_profile.py index bfe817c51..63094e3fe 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -24,7 +24,6 @@ from unicodetext import standardize_text from utils import get_person_icon from utils import replace_strings from utils import data_dir -from utils import time_days_ago from utils import get_attributed_to from utils import get_url_from_post from utils import get_memorials @@ -47,10 +46,11 @@ from utils import acct_dir from utils import get_supported_languages from utils import local_actor_url from utils import get_reply_interval_hours -from utils import get_account_timezone from utils import remove_eol from utils import get_actor_from_post from utils import resembles_url +from timeFunctions import time_days_ago +from timeFunctions import get_account_timezone from languages import get_actor_languages from skills import get_skills from theme import get_themes_list diff --git a/webapp_search.py b/webapp_search.py index d422a852f..6db48d967 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -13,11 +13,11 @@ import urllib.parse from flags import is_editor from flags import is_public_post from searchable import search_box_posts +from timeFunctions import date_from_string_format from utils import get_person_icon from utils import data_dir from utils import get_post_attachments from utils import get_url_from_post -from utils import date_from_string_format from utils import get_attributed_to from utils import get_actor_from_post_id from utils import remove_html