diff --git a/auth/jwtcodec.py b/auth/jwtcodec.py index 0c35dea5..87bd2b5a 100644 --- a/auth/jwtcodec.py +++ b/auth/jwtcodec.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone import jwt from base.exceptions import ExpiredToken, InvalidToken from validations.auth import TokenPayload, AuthInput @@ -8,13 +8,11 @@ from settings import JWT_ALGORITHM, JWT_SECRET_KEY class JWTCodec: @staticmethod def encode(user: AuthInput, exp: datetime) -> str: - expires = int(exp.timestamp() * 1000) - issued = int(datetime.now().timestamp() * 1000) + issued = datetime.now(tz=timezone.utc) payload = { "user_id": user.id, "username": user.email or user.phone, - # "device": device, # no use cases - "exp": expires, + "exp": exp, "iat": issued, "iss": "discours" } diff --git a/auth/tokenstorage.py b/auth/tokenstorage.py index 0d7a30e9..ef6fa0d6 100644 --- a/auth/tokenstorage.py +++ b/auth/tokenstorage.py @@ -9,7 +9,7 @@ from settings import SESSION_TOKEN_LIFE_SPAN, ONETIME_TOKEN_LIFE_SPAN async def save(token_key, life_span, auto_delete=True): await redis.execute("SET", token_key, "True") if auto_delete: - expire_at = (datetime.now() + timedelta(seconds=life_span)).timestamp() + expire_at = (datetime.now(tz=timezone.utc) + timedelta(seconds=life_span)).timestamp() await redis.execute("EXPIREAT", token_key, int(expire_at)) diff --git a/migration/__init__.py b/migration/__init__.py index a6aaa0ff..2d195e06 100644 --- a/migration/__init__.py +++ b/migration/__init__.py @@ -4,7 +4,7 @@ import json import os import subprocess import sys -from datetime import datetime +from datetime import datetime, timezone import bs4 from migration.tables.comments import migrate as migrateComment @@ -21,7 +21,7 @@ from orm import init_tables # from export import export_email_subscriptions from .export import export_mdx, export_slug -TODAY = datetime.strftime(datetime.now(), "%Y%m%d") +TODAY = datetime.strftime(datetime.now(tz=timezone.utc), "%Y%m%d") OLD_DATE = "2016-03-05 22:22:00.350000" diff --git a/migration/export.py b/migration/export.py index 75d95160..988ab35d 100644 --- a/migration/export.py +++ b/migration/export.py @@ -1,6 +1,6 @@ import json import os -from datetime import datetime +from datetime import datetime, timezone import frontmatter @@ -11,7 +11,7 @@ OLD_DATE = "2016-03-05 22:22:00.350000" EXPORT_DEST = "../discoursio-web/data/" parentDir = "/".join(os.getcwd().split("/")[:-1]) contentDir = parentDir + "/discoursio-web/content/" -ts = datetime.now() +ts = datetime.now(tz=timezone.utc) def get_metadata(r): diff --git a/migration/tables/comments.py b/migration/tables/comments.py index 567259b3..c93e3d63 100644 --- a/migration/tables/comments.py +++ b/migration/tables/comments.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from dateutil.parser import parse as date_parse @@ -10,7 +10,7 @@ from orm.topic import TopicFollower from orm.user import User from services.stat.reacted import ReactedStorage -ts = datetime.now() +ts = datetime.now(tz=timezone.utc) async def migrate(entry, storage): diff --git a/migration/tables/content_items.py b/migration/tables/content_items.py index 1a798103..af5f99d5 100644 --- a/migration/tables/content_items.py +++ b/migration/tables/content_items.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone import json from dateutil.parser import parse as date_parse from sqlalchemy.exc import IntegrityError @@ -13,7 +13,7 @@ from services.stat.reacted import ReactedStorage from services.stat.viewed import ViewedStorage OLD_DATE = "2016-03-05 22:22:00.350000" -ts = datetime.now() +ts = datetime.now(tz=timezone.utc) type2layout = { "Article": "article", "Literature": "literature", diff --git a/resolvers/auth.py b/resolvers/auth.py index c167394b..8f9fe0e9 100644 --- a/resolvers/auth.py +++ b/resolvers/auth.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from datetime import datetime +from datetime import datetime, timezone from urllib.parse import quote_plus from graphql.type import GraphQLResolveInfo @@ -26,7 +26,7 @@ from settings import SESSION_TOKEN_HEADER async def get_current_user(_, info): print('[resolvers.auth] get current user %s' % str(info)) user = info.context["request"].user - user.lastSeen = datetime.now() + user.lastSeen = datetime.now(tz=timezone.utc) with local_session() as session: session.add(user) session.commit() @@ -50,7 +50,7 @@ async def confirm_email(_, info, token): user = session.query(User).where(User.id == user_id).first() session_token = await TokenStorage.create_session(user) user.emailConfirmed = True - user.lastSeen = datetime.now() + user.lastSeen = datetime.now(tz=timezone.utc) session.add(user) session.commit() return { diff --git a/resolvers/create/collab.py b/resolvers/create/collab.py index 7db4620e..058a90c2 100644 --- a/resolvers/create/collab.py +++ b/resolvers/create/collab.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from auth.authenticate import login_required from base.orm import local_session @@ -37,7 +37,7 @@ async def invite_author(_, info, author, shout): if author.id in authors: return {"error": "already added"} shout.authors.append(author) - shout.updated_at = datetime.now() + shout.updated_at = datetime.now(tz=timezone.utc) session.add(shout) session.commit() @@ -63,7 +63,7 @@ async def remove_author(_, info, author, shout): if author.id not in authors: return {"error": "not in authors"} shout.authors.remove(author) - shout.updated_at = datetime.now() + shout.updated_at = datetime.now(tz=timezone.utc) session.add(shout) session.commit() diff --git a/resolvers/create/editor.py b/resolvers/create/editor.py index 5dbcf95c..220ff229 100644 --- a/resolvers/create/editor.py +++ b/resolvers/create/editor.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from auth.authenticate import login_required from base.orm import local_session @@ -71,7 +71,7 @@ async def update_shout(_, info, inp): return {"error": "access denied"} else: shout.update(inp) - shout.updatedAt = datetime.now() + shout.updatedAt = datetime.now(tz=timezone.utc) session.add(shout) if inp.get("topics"): # remove old links @@ -103,7 +103,7 @@ async def delete_shout(_, info, slug): return {"error": "access denied"} for a in authors: reactions_unfollow(a.slug, slug, True) - shout.deletedAt = datetime.now() + shout.deletedAt = datetime.now(tz=timezone.utc) session.add(shout) session.commit() diff --git a/resolvers/inbox/chats.py b/resolvers/inbox/chats.py index 1b80c2ea..f4b1ca1e 100644 --- a/resolvers/inbox/chats.py +++ b/resolvers/inbox/chats.py @@ -1,6 +1,6 @@ import json import uuid -from datetime import datetime +from datetime import datetime, timezone from auth.authenticate import login_required from base.redis import redis @@ -67,7 +67,7 @@ async def update_chat(_, info, chat_new: dict): chat.update({ "title": chat_new.get("title", chat["title"]), "description": chat_new.get("description", chat["description"]), - "updatedAt": int(datetime.now().timestamp()), + "updatedAt": int(datetime.now(tz=timezone.utc).timestamp()), "admins": chat_new.get("admins", chat["admins"]), "users": chat_new.get("users", chat["users"]) }) @@ -90,8 +90,8 @@ async def create_chat(_, info, title="", members=[]): members.append(user.slug) chat = { "title": title, - "createdAt": int(datetime.now().timestamp()), - "updatedAt": int(datetime.now().timestamp()), + "createdAt": int(datetime.now(tz=timezone.utc).timestamp()), + "updatedAt": int(datetime.now(tz=timezone.utc).timestamp()), "createdBy": user.slug, "id": chat_id, "users": members, diff --git a/resolvers/inbox/load.py b/resolvers/inbox/load.py index d3ca0ff1..cd38690b 100644 --- a/resolvers/inbox/load.py +++ b/resolvers/inbox/load.py @@ -1,5 +1,5 @@ import json -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from auth.authenticate import login_required from base.redis import redis @@ -83,7 +83,7 @@ async def load_messages_by(_, info, by, limit: int = 50, offset: int = 0): days = by.get("days") if days: messages = filter( - lambda m: datetime.now() - int(m["createdAt"]) < timedelta(days=by.get("days")), + lambda m: datetime.now(tz=timezone.utc) - int(m["createdAt"]) < timedelta(days=by.get("days")), messages ) return { diff --git a/resolvers/inbox/messages.py b/resolvers/inbox/messages.py index 48f45b4a..84734a61 100644 --- a/resolvers/inbox/messages.py +++ b/resolvers/inbox/messages.py @@ -1,6 +1,6 @@ import asyncio import json -from datetime import datetime +from datetime import datetime, timezone from auth.authenticate import login_required from base.redis import redis @@ -28,7 +28,7 @@ async def create_message(_, info, chat: str, body: str, replyTo=None): "author": user.slug, "body": body, "replyTo": replyTo, - "createdAt": int(datetime.now().timestamp()), + "createdAt": int(datetime.now(tz=timezone.utc).timestamp()), } await redis.execute( "SET", f"chats/{chat['id']}/messages/{message_id}", json.dumps(new_message) @@ -70,7 +70,7 @@ async def update_message(_, info, chat_id: str, message_id: int, body: str): return {"error": "access denied"} message["body"] = body - message["updatedAt"] = int(datetime.now().timestamp()) + message["updatedAt"] = int(datetime.now(tz=timezone.utc).timestamp()) await redis.execute("SET", f"chats/{chat_id}/messages/{message_id}", json.dumps(message)) diff --git a/resolvers/zine/load.py b/resolvers/zine/load.py index 4f37f9c2..81141ac6 100644 --- a/resolvers/zine/load.py +++ b/resolvers/zine/load.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import sqlalchemy as sa from sqlalchemy.orm import selectinload from sqlalchemy.sql.expression import desc, asc, select, case @@ -27,7 +27,7 @@ def apply_filters(q, filters, user=None): if filters.get("body"): q = q.filter(Shout.body.ilike(f'%{filters.get("body")}%s')) if filters.get("days"): - before = datetime.now() - timedelta(days=int(filters.get("days")) or 30) + before = datetime.now(tz=timezone.utc) - timedelta(days=int(filters.get("days")) or 30) q = q.filter(Shout.createdAt > before) return q diff --git a/resolvers/zine/profile.py b/resolvers/zine/profile.py index 911c6058..cbb5d4c3 100644 --- a/resolvers/zine/profile.py +++ b/resolvers/zine/profile.py @@ -1,5 +1,5 @@ from typing import List -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from sqlalchemy import and_, func from sqlalchemy.orm import selectinload @@ -203,10 +203,10 @@ async def load_authors_by(_, info, by, limit, offset): aaa = list(map(lambda a: a.slug, TopicStat.authors_by_topic.get(by["topic"]))) aq = aq.filter(User.name._in(aaa)) if by.get("lastSeen"): # in days - days_before = datetime.now() - timedelta(days=by["lastSeen"]) + days_before = datetime.now(tz=timezone.utc) - timedelta(days=by["lastSeen"]) aq = aq.filter(User.lastSeen > days_before) elif by.get("createdAt"): # in days - days_before = datetime.now() - timedelta(days=by["createdAt"]) + days_before = datetime.now(tz=timezone.utc) - timedelta(days=by["createdAt"]) aq = aq.filter(User.createdAt > days_before) aq = aq.group_by( User.id diff --git a/resolvers/zine/reactions.py b/resolvers/zine/reactions.py index 1f4d48c2..646de03a 100644 --- a/resolvers/zine/reactions.py +++ b/resolvers/zine/reactions.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from sqlalchemy import and_, asc, desc, select, text, func from sqlalchemy.orm import aliased @@ -109,7 +109,7 @@ def check_to_hide(session, user, reaction): def set_published(session, slug, publisher): s = session.query(Shout).where(Shout.slug == slug).first() - s.publishedAt = datetime.now() + s.publishedAt = datetime.now(tz=timezone.utc) s.publishedBy = publisher s.visibility = text('public') session.add(s) @@ -166,7 +166,7 @@ async def update_reaction(_, info, inp): if reaction.createdBy != user.slug: return {"error": "access denied"} reaction.body = inp["body"] - reaction.updatedAt = datetime.now() + reaction.updatedAt = datetime.now(tz=timezone.utc) if reaction.kind != inp["kind"]: # NOTE: change mind detection can be here pass @@ -191,7 +191,7 @@ async def delete_reaction(_, info, rid): return {"error": "invalid reaction id"} if reaction.createdBy != user.slug: return {"error": "access denied"} - reaction.deletedAt = datetime.now() + reaction.deletedAt = datetime.now(tz=timezone.utc) session.commit() return {} @@ -240,7 +240,7 @@ async def load_reactions_by(_, _info, by, limit=50, offset=0): if by.get('search', 0) > 2: q = q.filter(Reaction.body.ilike(f'%{by["body"]}%')) if by.get("days"): - after = datetime.now() - timedelta(days=int(by["days"]) or 30) + after = datetime.now(tz=timezone.utc) - timedelta(days=int(by["days"]) or 30) q = q.filter(Reaction.createdAt > after) order_way = asc if by.get("sort", "").startswith("-") else desc order_field = by.get("sort") or Reaction.createdAt diff --git a/schema.graphql b/schema.graphql index e42e61db..ba62a678 100644 --- a/schema.graphql +++ b/schema.graphql @@ -478,7 +478,7 @@ type TopicStat { authors: Int! # viewed: Int # reacted: Int! - #commented: Int + # commented: Int # rating: Int }