diff --git a/app/activitypub/routes.py b/app/activitypub/routes.py index fdd50b7a..c182d132 100644 --- a/app/activitypub/routes.py +++ b/app/activitypub/routes.py @@ -10,7 +10,7 @@ from app.post.routes import continue_discussion, show_post from app.user.routes import show_profile from app.constants import POST_TYPE_LINK, POST_TYPE_IMAGE, SUBSCRIPTION_MEMBER from app.models import User, Community, CommunityJoinRequest, CommunityMember, CommunityBan, ActivityPubLog, Post, \ - PostReply, Instance, PostVote, PostReplyVote, File, AllowedInstances, BannedInstances + PostReply, Instance, PostVote, PostReplyVote, File, AllowedInstances, BannedInstances, utcnow from app.activitypub.util import public_key, users_total, active_half_year, active_month, local_posts, local_comments, \ post_to_activity, find_actor_or_create, default_context, instance_blocked, find_reply_parent, find_liked_object, \ lemmy_site_data, instance_weight, is_activitypub_request @@ -125,9 +125,9 @@ def lemmy_federated_instances(): instance_data['version'] = instance.version linked.append(instance_data) for instance in AllowedInstances.query.all(): - allowed.append({"id": instance.id, "domain": instance.domain, "published": datetime.utcnow(), "updated": datetime.utcnow()}) + allowed.append({"id": instance.id, "domain": instance.domain, "published": utcnow(), "updated": utcnow()}) for instance in BannedInstances.query.all(): - blocked.append({"id": instance.id, "domain": instance.domain, "published": datetime.utcnow(), "updated": datetime.utcnow()}) + blocked.append({"id": instance.id, "domain": instance.domain, "published": utcnow(), "updated": utcnow()}) return jsonify({ "federated_instances": { "linked": linked, @@ -290,7 +290,7 @@ def shared_inbox(): community = find_actor_or_create(community_ap_id) user = find_actor_or_create(user_ap_id) if user and community: - user.last_seen = community.last_active = datetime.utcnow() + user.last_seen = community.last_active = utcnow() object_type = request_json['object']['type'] new_content_types = ['Page', 'Article', 'Link', 'Note'] @@ -348,7 +348,7 @@ def shared_inbox(): if post is not None: db.session.add(post) community.post_count += 1 - community.last_active = datetime.utcnow() + community.last_active = utcnow() activity_log.result = 'success' db.session.commit() vote = PostVote(user_id=user.id, author_id=post.user_id, @@ -382,7 +382,7 @@ def shared_inbox(): db.session.add(post_reply) post.reply_count += 1 community.post_reply_count += 1 - community.last_active = post.last_active = datetime.utcnow() + community.last_active = post.last_active = utcnow() activity_log.result = 'success' db.session.commit() vote = PostReplyVote(user_id=user.id, author_id=post_reply.user_id, post_reply_id=post_reply.id, @@ -400,7 +400,7 @@ def shared_inbox(): community = find_actor_or_create(community_ap_id) user = find_actor_or_create(user_ap_id) if user and community: - user.last_seen = community.last_active = datetime.utcnow() + user.last_seen = community.last_active = utcnow() object_type = request_json['object']['object']['type'] new_content_types = ['Page', 'Article', 'Link', 'Note'] if object_type in new_content_types: # create a new post @@ -531,7 +531,7 @@ def shared_inbox(): banned = CommunityBan.query.filter_by(user_id=user.id, community_id=community.id).first() if banned is None: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() if community_membership(user, community) != SUBSCRIPTION_MEMBER: member = CommunityMember(user_id=user.id, community_id=community.id) db.session.add(member) @@ -592,7 +592,7 @@ def shared_inbox(): user = find_actor_or_create(user_ap_id) community = find_actor_or_create(community_ap_id) if user and community: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() member = CommunityMember.query.filter_by(user_id=user.id, community_id=community.id).first() join_request = CommunityJoinRequest.query.filter_by(user_id=user.id, community_id=community.id).first() @@ -614,7 +614,7 @@ def shared_inbox(): if '/post/' in target_ap_id: post = Post.query.filter_by(ap_id=target_ap_id).first() if user and post: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() existing_vote = PostVote.query.filter_by(user_id=user.id, post_id=post.id).first() if existing_vote: post.author.reputation -= existing_vote.effect @@ -677,7 +677,7 @@ def shared_inbox(): elif 'content' in request_json['object']: post.body_html = allowlist_html(request_json['object']['content']) post.body = html_to_markdown(post.body_html) - post.edited_at = datetime.utcnow() + post.edited_at = utcnow() db.session.commit() activity_log.result = 'success' elif request_json['object']['type'] == 'Note': # Editing a reply @@ -690,7 +690,7 @@ def shared_inbox(): elif 'content' in request_json['object']: reply.body_html = allowlist_html(request_json['object']['content']) reply.body = html_to_markdown(reply.body_html) - reply.edited_at = datetime.utcnow() + reply.edited_at = utcnow() db.session.commit() activity_log.result = 'success' elif request_json['type'] == 'Delete': @@ -722,7 +722,7 @@ def shared_inbox(): if '/post/' in target_ap_id: post = Post.query.filter_by(ap_id=target_ap_id).first() if user and post: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() existing_vote = PostVote.query.filter_by(user_id=user.id, post_id=post.id).first() if not existing_vote: post.up_votes += 1 @@ -748,7 +748,7 @@ def shared_inbox(): db.session.add(vote) activity_log.result = 'success' elif user and comment: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() existing_vote = PostReplyVote.query.filter_by(user_id=user.id, post_reply_id=comment.id).first() if not existing_vote: @@ -792,7 +792,7 @@ def shared_inbox(): if '/post/' in target_ap_id: post = Post.query.filter_by(ap_id=target_ap_id).first() if user and comment: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() existing_vote = PostReplyVote.query.filter_by(user_id=user.id, post_reply_id=comment.id).first() if not existing_vote: @@ -823,7 +823,7 @@ def shared_inbox(): pass # they have already downvoted this reply activity_log.result = 'success' elif user and post: - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() existing_vote = PostVote.query.filter_by(user_id=user.id, post_id=post.id).first() if not existing_vote: effect = -1.0 diff --git a/app/activitypub/signature.py b/app/activitypub/signature.py index 16b49c04..6be4ca47 100644 --- a/app/activitypub/signature.py +++ b/app/activitypub/signature.py @@ -46,6 +46,7 @@ from pyld import jsonld from app.activitypub.util import default_context from app.constants import DATETIME_MS_FORMAT +from app.models import utcnow def http_date(epoch_seconds=None): @@ -392,7 +393,7 @@ class LDSignature: options: dict[str, str] = { "@context": "https://w3id.org/identity/v1", "creator": key_id, - "created": format_ld_date(datetime.utcnow()), + "created": format_ld_date(utcnow()), } # Get the normalised hash of each document final_hash = cls.normalized_hash(options) + cls.normalized_hash(document) diff --git a/app/activitypub/util.py b/app/activitypub/util.py index 7a176f11..64cf71df 100644 --- a/app/activitypub/util.py +++ b/app/activitypub/util.py @@ -5,7 +5,7 @@ from typing import Union, Tuple from flask import current_app, request from sqlalchemy import text from app import db, cache -from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance +from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow import time import base64 import requests @@ -246,7 +246,7 @@ def find_actor_or_create(actor: str) -> Union[User, Community, None]: ap_inbox_url=activity_json['endpoints']['sharedInbox'], ap_followers_url=activity_json['followers'] if 'followers' in activity_json else None, ap_preferred_username=activity_json['preferredUsername'], - ap_fetched_at=datetime.utcnow(), + ap_fetched_at=utcnow(), ap_domain=server, public_key=activity_json['publicKey']['publicKeyPem'], # language=community_json['language'][0]['identifier'] # todo: language @@ -277,7 +277,7 @@ def find_actor_or_create(actor: str) -> Union[User, Community, None]: ap_profile_id=activity_json['id'], ap_followers_url=activity_json['followers'], ap_inbox_url=activity_json['endpoints']['sharedInbox'], - ap_fetched_at=datetime.utcnow(), + ap_fetched_at=utcnow(), ap_domain=server, public_key=activity_json['publicKey']['publicKeyPem'], # language=community_json['language'][0]['identifier'] # todo: language diff --git a/app/admin/routes.py b/app/admin/routes.py index 9fad1391..cc2e07cf 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -49,7 +49,7 @@ def admin_home(): @permission_required('change instance settings') def admin_activities(): db.session.query(ActivityPubLog).filter( - ActivityPubLog.created_at < datetime.utcnow() - timedelta(days=3)).delete() + ActivityPubLog.created_at < aware_utcnow() - timedelta(days=3)).delete() db.session.commit() return render_template('admin/activities.html', title=_('ActivityPub Log'), diff --git a/app/auth/routes.py b/app/auth/routes.py index 8aa2b0e2..72ef2ea5 100644 --- a/app/auth/routes.py +++ b/app/auth/routes.py @@ -7,7 +7,7 @@ from app import db from app.auth import bp from app.auth.forms import LoginForm, RegistrationForm, ResetPasswordRequestForm, ResetPasswordForm from app.auth.util import random_token -from app.models import User +from app.models import User, utcnow from app.auth.email import send_password_reset_email, send_welcome_email, send_verification_email from app.activitypub.signature import RsaKeys from app.utils import render_template @@ -41,7 +41,7 @@ def login(): flash(_('Invalid password')) return redirect(url_for('auth.login')) login_user(user, remember=True) - current_user.last_seen = datetime.utcnow() + current_user.last_seen = utcnow() current_user.verification_token = '' db.session.commit() next_page = request.args.get('next') @@ -143,7 +143,7 @@ def verify_email(token): if user.verified: # guard against users double-clicking the link in the email return redirect(url_for('main.index')) user.verified = True - user.last_seen = datetime.utcnow() + user.last_seen = utcnow() private_key, public_key = RsaKeys.generate_keypair() user.private_key = private_key user.public_key = public_key diff --git a/app/cli.py b/app/cli.py index 47b9bb82..6374f356 100644 --- a/app/cli.py +++ b/app/cli.py @@ -10,7 +10,8 @@ import os from app.auth.email import send_verification_email from app.auth.util import random_token -from app.models import Settings, BannedInstances, Interest, Role, User, RolePermission, Domain, ActivityPubLog +from app.models import Settings, BannedInstances, Interest, Role, User, RolePermission, Domain, ActivityPubLog, \ + utcnow from app.utils import file_get_contents, retrieve_block_list @@ -125,7 +126,7 @@ def register(app): with app.app_context(): """Remove activity older than 3 days""" db.session.query(ActivityPubLog).filter( - ActivityPubLog.created_at < datetime.utcnow() - timedelta(days=3)).delete() + ActivityPubLog.created_at < utcnow() - timedelta(days=3)).delete() db.session.commit() diff --git a/app/community/routes.py b/app/community/routes.py index dcc3c3bf..7ea18c36 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -13,7 +13,7 @@ from app.community.util import search_for_community, community_url_exists, actor from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LINK, POST_TYPE_ARTICLE, POST_TYPE_IMAGE, \ SUBSCRIPTION_PENDING from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \ - File, PostVote + File, PostVote, utcnow from app.community import bp from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \ shorten_string, markdown_to_text, domain_from_url, validate_image, gibberish, community_membership, ap_datetime, \ @@ -259,7 +259,7 @@ def add_post(actor): post = Post(user_id=current_user.id, community_id=form.communities.data) save_post(form, post) community.post_count += 1 - community.last_active = datetime.utcnow() + community.last_active = utcnow() db.session.commit() post.ap_id = f"https://{current_app.config['SERVER_NAME']}/post/{post.id}" db.session.commit() @@ -285,7 +285,7 @@ def add_post(actor): 'commentsEnabled': post.comments_enabled, 'sensitive': post.nsfw, 'nsfl': post.nsfl, - 'published': ap_datetime(datetime.utcnow()), + 'published': ap_datetime(utcnow()), 'audience': community.ap_profile_id } create = { diff --git a/app/community/util.py b/app/community/util.py index 92f28ecf..6749a1d4 100644 --- a/app/community/util.py +++ b/app/community/util.py @@ -9,7 +9,7 @@ from pillow_heif import register_heif_opener from app import db, cache from app.constants import POST_TYPE_ARTICLE, POST_TYPE_LINK, POST_TYPE_IMAGE -from app.models import Community, File, BannedInstances, PostReply, PostVote, Post +from app.models import Community, File, BannedInstances, PostReply, PostVote, Post, utcnow from app.utils import get_request, gibberish, markdown_to_html, domain_from_url, validate_image from sqlalchemy import desc, text import os @@ -59,7 +59,7 @@ def search_for_community(address: str): ap_followers_url=community_json['followers'], ap_inbox_url=community_json['endpoints']['sharedInbox'], ap_moderators_url=community_json['attributedTo'] if 'attributedTo' in community_json else None, - ap_fetched_at=datetime.utcnow(), + ap_fetched_at=utcnow(), ap_domain=server, public_key=community_json['publicKey']['publicKeyPem'], # language=community_json['language'][0]['identifier'] # todo: language diff --git a/app/models.py b/app/models.py index e22bc9cc..bc50c021 100644 --- a/app/models.py +++ b/app/models.py @@ -1,5 +1,4 @@ -from datetime import datetime, timedelta, date -from hashlib import md5 +from datetime import datetime, timedelta, date, timezone from time import time from typing import List @@ -20,6 +19,11 @@ from app.constants import SUBSCRIPTION_NONMEMBER, SUBSCRIPTION_MEMBER, SUBSCRIPT SUBSCRIPTION_BANNED, SUBSCRIPTION_PENDING +# same as datetime.utcnow() except with the UTC timezone explicitly added. datetime.utcnow() is depreciated in python 3.12+ +def utcnow(): + return datetime.now(timezone.utc) + + class FullTextSearchQuery(BaseQuery, SearchQueryMixin): pass @@ -71,8 +75,8 @@ class Community(db.Model): post_reply_count = db.Column(db.Integer, default=0) nsfw = db.Column(db.Boolean, default=False) nsfl = db.Column(db.Boolean, default=False) - created_at = db.Column(db.DateTime, default=datetime.utcnow) - last_active = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) + last_active = db.Column(db.DateTime, default=utcnow) public_key = db.Column(db.Text) private_key = db.Column(db.Text) @@ -193,8 +197,8 @@ class User(UserMixin, db.Model): keywords = db.Column(db.String(256)) show_nsfw = db.Column(db.Boolean, default=False) show_nsfl = db.Column(db.Boolean, default=False) - created = db.Column(db.DateTime, default=datetime.utcnow) - last_seen = db.Column(db.DateTime, default=datetime.utcnow, index=True) + created = db.Column(db.DateTime, default=utcnow) + last_seen = db.Column(db.DateTime, default=utcnow, index=True) avatar_id = db.Column(db.Integer, db.ForeignKey('file.id')) cover_id = db.Column(db.Integer, db.ForeignKey('file.id')) public_key = db.Column(db.Text) @@ -307,12 +311,12 @@ class User(UserMixin, db.Model): def expires_soon(self): if self.expires is None: return False - return self.expires < datetime.utcnow() + timedelta(weeks=1) + return self.expires < utcnow() + timedelta(weeks=1) def is_expired(self): if self.expires is None: return True - return self.expires < datetime.utcnow() + return self.expires < utcnow() def expired_ages_ago(self): if self.expires is None: @@ -347,7 +351,9 @@ class User(UserMixin, db.Model): return self.ap_profile_id if self.ap_profile_id else f"https://{current_app.config['SERVER_NAME']}/u/{self.user_name}" def created_recently(self): - return self.created and self.created > datetime.utcnow() - timedelta(days=7) + if self.created.tzinfo is None: + self.created = self.created.replace(tzinfo=timezone.utc) + return self.created and self.created > utcnow() - timedelta(days=7) @staticmethod def verify_reset_password_token(token): @@ -394,7 +400,7 @@ class ActivityLog(db.Model): user_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True) activity_type = db.Column(db.String(64)) activity = db.Column(db.String(255)) - timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) + timestamp = db.Column(db.DateTime, index=True, default=utcnow) class Post(db.Model): @@ -420,9 +426,9 @@ class Post(db.Model): notify_author = db.Column(db.Boolean, default=True) indexable = db.Column(db.Boolean, default=False) from_bot = db.Column(db.Boolean, default=False) - created_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) # this is when the content arrived here - posted_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) # this is when the original server created it - last_active = db.Column(db.DateTime, index=True, default=datetime.utcnow) + created_at = db.Column(db.DateTime, index=True, default=utcnow) # this is when the content arrived here + posted_at = db.Column(db.DateTime, index=True, default=utcnow) # this is when the original server created it + last_active = db.Column(db.DateTime, index=True, default=utcnow) ip = db.Column(db.String(50)) up_votes = db.Column(db.Integer, default=0) down_votes = db.Column(db.Integer, default=0) @@ -492,8 +498,8 @@ class PostReply(db.Model): nsfw = db.Column(db.Boolean, default=False) nsfl = db.Column(db.Boolean, default=False) notify_author = db.Column(db.Boolean, default=True) - created_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) - posted_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) + created_at = db.Column(db.DateTime, index=True, default=utcnow) + posted_at = db.Column(db.DateTime, index=True, default=utcnow) ip = db.Column(db.String(50)) from_bot = db.Column(db.Boolean, default=False) up_votes = db.Column(db.Integer, default=0) @@ -548,13 +554,13 @@ class Domain(db.Model): class DomainBlock(db.Model): user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) domain_id = db.Column(db.Integer, db.ForeignKey('domain.id'), primary_key=True) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class CommunityBlock(db.Model): user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) community_id = db.Column(db.Integer, db.ForeignKey('community.id'), primary_key=True) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class CommunityMember(db.Model): @@ -563,7 +569,7 @@ class CommunityMember(db.Model): is_moderator = db.Column(db.Boolean, default=False) is_owner = db.Column(db.Boolean, default=False) is_banned = db.Column(db.Boolean, default=False) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) # people banned from communities @@ -572,7 +578,7 @@ class CommunityBan(db.Model): community_id = db.Column(db.Integer, db.ForeignKey('community.id'), primary_key=True) banned_by = db.Column(db.Integer, db.ForeignKey('user.id')) reason = db.Column(db.String(50)) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) ban_until = db.Column(db.DateTime) @@ -581,14 +587,14 @@ class UserNote(db.Model): user_id = db.Column(db.Integer, db.ForeignKey('user.id')) target_id = db.Column(db.Integer, db.ForeignKey('user.id')) body = db.Column(db.Text) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class UserBlock(db.Model): id = db.Column(db.Integer, primary_key=True) blocker_id = db.Column(db.Integer, db.ForeignKey('user.id')) blocked_id = db.Column(db.Integer, db.ForeignKey('user.id')) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class BannedInstances(db.Model): @@ -596,13 +602,13 @@ class BannedInstances(db.Model): domain = db.Column(db.String(256), index=True) reason = db.Column(db.String(256)) initiator = db.Column(db.String(256)) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class AllowedInstances(db.Model): id = db.Column(db.Integer, primary_key=True) domain = db.Column(db.String(256), index=True) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class Instance(db.Model): @@ -614,8 +620,8 @@ class Instance(db.Model): vote_weight = db.Column(db.Float, default=1.0) software = db.Column(db.String(50)) version = db.Column(db.String(50)) - created_at = db.Column(db.DateTime, default=datetime.utcnow) - updated_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) + updated_at = db.Column(db.DateTime, default=utcnow) class Settings(db.Model): @@ -647,7 +653,7 @@ class PostVote(db.Model): author_id = db.Column(db.Integer, db.ForeignKey('user.id')) post_id = db.Column(db.Integer, db.ForeignKey('post.id')) effect = db.Column(db.Float) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) post = db.relationship('Post', foreign_keys=[post_id]) @@ -657,7 +663,7 @@ class PostReplyVote(db.Model): author_id = db.Column(db.Integer, db.ForeignKey('user.id')) # the author of the reply voted on - who's reputation is affected post_reply_id = db.Column(db.Integer, db.ForeignKey('post_reply.id')) effect = db.Column(db.Float) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) # save every activity to a log, to aid debugging @@ -669,7 +675,7 @@ class ActivityPubLog(db.Model): activity_json = db.Column(db.Text) # the full json of the activity result = db.Column(db.String(10)) # 'success' or 'failure' exception_message = db.Column(db.Text) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) class Filter(db.Model): @@ -707,7 +713,7 @@ class Notification(db.Model): read = db.Column(db.Boolean, default=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) - created_at = db.Column(db.DateTime, default=datetime.utcnow) + created_at = db.Column(db.DateTime, default=utcnow) @login.user_loader diff --git a/app/post/routes.py b/app/post/routes.py index 00b0c636..6853832c 100644 --- a/app/post/routes.py +++ b/app/post/routes.py @@ -14,7 +14,7 @@ from app.community.forms import CreatePostForm from app.post.util import post_replies, get_comment_branch, post_reply_count from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LINK, POST_TYPE_ARTICLE, POST_TYPE_IMAGE from app.models import Post, PostReply, \ - PostReplyVote, PostVote, Notification + PostReplyVote, PostVote, Notification, utcnow from app.post import bp from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \ shorten_string, markdown_to_text, domain_from_url, validate_image, gibberish, ap_datetime, return_304, \ @@ -43,7 +43,7 @@ def show_post(post_id: int): notification = Notification(title=_('Reply: ') + shorten_string(form.body.data), user_id=post.user_id, author_id=current_user.id, url=url_for('activitypub.post_ap', post_id=post.id)) db.session.add(notification) - post.last_active = post.community.last_active = datetime.utcnow() + post.last_active = post.community.last_active = utcnow() post.reply_count += 1 post.community.post_reply_count += 1 @@ -78,7 +78,7 @@ def show_post(post_id: int): 'content': reply.body, 'mediaType': 'text/markdown' }, - 'published': ap_datetime(datetime.utcnow()), + 'published': ap_datetime(utcnow()), 'distinguished': False, 'audience': post.community.profile_id() } @@ -171,7 +171,7 @@ def post_vote(post_id: int, vote_direction): effect=effect) post.author.reputation += effect db.session.add(vote) - current_user.last_seen = datetime.utcnow() + current_user.last_seen = utcnow() db.session.commit() post.flush_cache() return render_template('post/_post_voting_buttons.html', post=post, @@ -223,7 +223,7 @@ def comment_vote(comment_id, vote_direction): vote = PostReplyVote(user_id=current_user.id, post_reply_id=comment_id, author_id=comment.author.id, effect=effect) comment.author.reputation += effect db.session.add(vote) - current_user.last_seen = datetime.utcnow() + current_user.last_seen = utcnow() db.session.commit() comment.post.flush_cache() return render_template('post/_voting_buttons.html', comment=comment, @@ -252,7 +252,7 @@ def add_reply(post_id: int, comment_id: int): is_moderator = current_user.is_authenticated and any(mod.user_id == current_user.id for mod in mods) form = NewReplyForm() if form.validate_on_submit(): - current_user.last_seen = datetime.utcnow() + current_user.last_seen = utcnow() reply = PostReply(user_id=current_user.id, post_id=post.id, parent_id=in_reply_to.id, depth=in_reply_to.depth + 1, community_id=post.community.id, body=form.body.data, body_html=markdown_to_html(form.body.data), body_html_safe=True, @@ -270,7 +270,7 @@ def add_reply(post_id: int, comment_id: int): effect=1.0) db.session.add(reply_vote) post.reply_count = post_reply_count(post.id) - post.last_active = post.community.last_active = datetime.utcnow() + post.last_active = post.community.last_active = utcnow() db.session.commit() form.body.data = '' flash('Your comment has been added.') @@ -299,7 +299,7 @@ def add_reply(post_id: int, comment_id: int): 'content': reply.body, 'mediaType': 'text/markdown' }, - 'published': ap_datetime(datetime.utcnow()), + 'published': ap_datetime(utcnow()), 'distinguished': False, 'audience': post.community.profile_id(), 'contentMap': { @@ -373,8 +373,8 @@ def post_edit(post_id: int): if form.validate_on_submit(): save_post(form, post) - post.community.last_active = datetime.utcnow() - post.edited_at = datetime.utcnow() + post.community.last_active = utcnow() + post.edited_at = utcnow() db.session.commit() post.flush_cache() flash(_('Your changes have been saved.'), 'success') diff --git a/app/user/routes.py b/app/user/routes.py index 1d79c70c..64c63688 100644 --- a/app/user/routes.py +++ b/app/user/routes.py @@ -5,7 +5,7 @@ from flask_login import login_user, logout_user, current_user, login_required from flask_babel import _ from app import db, cache -from app.models import Post, Community, CommunityMember, User, PostReply, PostVote, Notification +from app.models import Post, Community, CommunityMember, User, PostReply, PostVote, Notification, utcnow from app.user import bp from app.user.forms import ProfileForm, SettingsForm from app.utils import get_setting, render_template, markdown_to_html, user_access, markdown_to_text, shorten_string @@ -210,7 +210,7 @@ def ban_purge_profile(actor): def notifications(): """Remove notifications older than 30 days""" db.session.query(Notification).filter( - Notification.created_at < datetime.utcnow() - timedelta(days=30)).delete() + Notification.created_at < utcnow() - timedelta(days=30)).delete() db.session.commit() # Update unread notifications count