diff --git a/.flake8 b/.flake8 deleted file mode 100644 index d557902..0000000 --- a/.flake8 +++ /dev/null @@ -1,6 +0,0 @@ -[flake8] -ignore = E203,W504,W191,W503 -exclude = .git -max-complexity = 10 -max-line-length = 108 -indent-string = ' ' diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 12a8730..d9c99bb 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,9 @@ +[0.2.13] +- migrated to pyproject and poetry +- validators added +- fixed graphql requests for core api +- uses official redis[hiredis] async + [0.2.12] - sigil is back for test diff --git a/Dockerfile b/Dockerfile index 610e90b..bc420fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,20 @@ +# Use an official Python runtime as a parent image FROM python:slim + +# Set the working directory in the container to /app WORKDIR /app +# Add metadata to the image to describe that the container is listening on port 80 EXPOSE 80 -COPY requirements.txt . -RUN apt-get update && apt-get install -y gcc && pip install -r requirements.txt -COPY . . -CMD ["python", "server.py"] + +# Copy the current directory contents into the container at /app +COPY . /app + +# Install any needed packages specified in pyproject.toml +RUN apt-get update && apt-get install -y gcc curl && \ + curl -sSL https://install.python-poetry.org | python - && \ + poetry config virtualenvs.create false && \ + poetry install --no-dev + +# Run server.py when the container launches +CMD ["python", "server.py"] \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..486139e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,54 @@ +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +name = "discoursio-inbox" +version = "0.2.13" +description = "Inbox server for discours.io" +authors = ["Tony Rewin "] + +[tool.poetry.dependencies] +python = "^3.8" +sentry-sdk = "^1.4.3" +redis = {extras = ["hiredis"], version = "^3.5.3"} +ariadne = "^0.13.0" +starlette = "^0.14.2" +uvicorn = "^0.15.0" +httpx = "^0.18.2" +itsdangerous = "^2.0.1" + +[tool.poetry.dev-dependencies] +pytest = "^6.2.5" + +[tool.black] +line-length = 120 +target-version = ['py312'] +include = '\.pyi?$' +exclude = ''' + +( + /( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + )/ + | foo.py # also separately exclude a file named foo.py in + # the root of the project +) +''' + +[tool.isort] +multi_line_output = 3 +include_trailing_comma = true +force_grid_wrap = 0 +use_parentheses = true +ensure_newline_before_comments = true +line_length = 120 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index fc4bb1c..0000000 --- a/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -sentry-sdk -redis[hiredis] -ariadne -starlette -uvicorn -httpx -itsdangerous -######## development deps -isort -brunette -flake8 -mypy -its diff --git a/resolvers/chats.py b/resolvers/chats.py index 4e3756c..c7ed614 100644 --- a/resolvers/chats.py +++ b/resolvers/chats.py @@ -1,7 +1,7 @@ import json import uuid from datetime import datetime, timezone -from validators.chat import Chat +from validators.inbox import Chat from services.auth import login_required from services.redis import redis from services.schema import mutation @@ -85,6 +85,9 @@ async def create_chat(_, info, title="", members=None): for member_id in members: await redis.execute("SADD", f"chats_by_author/{member_id}", chat_id) + + print(f"[resolvers.chatss] creating: {chat}") + await redis.execute("SET", f"chats/{chat_id}", json.dumps(chat)) await redis.execute("SET", f"chats/{chat_id}/next_message_id", str(0)) diff --git a/resolvers/load.py b/resolvers/load.py index 4b5a8dd..530dfdd 100644 --- a/resolvers/load.py +++ b/resolvers/load.py @@ -4,7 +4,7 @@ from services.core import get_author, get_network from services.redis import redis from services.auth import login_required from services.schema import query -from validators.chat import Message, Chat, ChatMember +from validators.inbox import Message, Chat, ChatMember from .chats import create_chat from .unread import get_unread_counter import asyncio @@ -60,7 +60,7 @@ async def load_chats( if len(cids) == 0: print(f"[resolvers.load] no chats for user with id={author_id}") r = await create_chat(None, info, members=[2]) # member with id = 2 is discours - print(f"[resolvers.load] created chat: {r}") + print(f"[resolvers.load] created chat: {r['chat']}") cids.append(r["chat"]["id"]) for cid in cids: async with lock: @@ -74,7 +74,6 @@ async def load_chats( c["members"] = [] for member_id in member_ids: a = await get_author(member_id) - print(f"[resolvers.load] author with id={member_id}: {a}") if a: a["online"] = a.get("id") in members_online c["members"].append(a) diff --git a/resolvers/messages.py b/resolvers/messages.py index a47d915..d0dfbae 100644 --- a/resolvers/messages.py +++ b/resolvers/messages.py @@ -1,7 +1,7 @@ import json from datetime import datetime, timezone from typing import List -from validators.chat import Message +from validators.inbox import Message from services.auth import login_required from services.presence import notify_message from services.redis import redis diff --git a/services/auth.py b/services/auth.py index 096eb6b..6f244be 100644 --- a/services/auth.py +++ b/services/auth.py @@ -47,7 +47,7 @@ async def check_auth(req): is_authenticated = user_id is not None return is_authenticated, user_id except Exception as e: - print(f"response contains no proper data: {r}") + print(f"{e}: {r}") return False, None diff --git a/services/core.py b/services/core.py index 51fcaaf..9b169ad 100644 --- a/services/core.py +++ b/services/core.py @@ -9,7 +9,9 @@ headers = {"Content-Type": "application/json"} async def get_author(author_id): gql = { - "query": "query GetAuthorById($author_id: Int!) { getAuthorById(author_id: $author_id) { id slug userpic name lastSeen } }", + "query": '''query GetAuthorById($author_id: Int!) { + getAuthorById(author_id: $author_id) { id slug userpic name lastSeen } + }''', "operation": "GetAuthorById", "variables": {"author_id": author_id}, } @@ -18,9 +20,7 @@ async def get_author(author_id): response = await client.post( API_BASE, headers=headers, data=json.dumps(gql) ) - print( - f"[services.core] get_author response: {response.status_code} {response.text}" - ) + print(f"[services.core] get_author: {response.status_code} {response.text}") if response.status_code != 200: return None r = response.json() @@ -33,7 +33,11 @@ async def get_author(author_id): async def get_network(author_id: int, limit: int = 50, offset: int = 0) -> list: gql = { - "query": "query LoadAuthors($author_id: Int!, $limit: Int, $offset: Int) { authorFollowings(author_id: $author_id, limit: $limit, offset: $offset) { id slug userpic name } }", + "query": '''query LoadAuthors($author_id: Int!, $limit: Int, $offset: Int) { + authorFollowings(author_id: $author_id, limit: $limit, offset: $offset) { + id slug userpic name + } + }''', "operation": "LoadAuthors", "variables": {"author_id": author_id, "limit": limit, "offset": offset}, } @@ -60,7 +64,11 @@ async def get_network(author_id: int, limit: int = 50, offset: int = 0) -> list: async def get_followers(author_id, amount): gql = { - "query": "query LoadAuthors($author_id: Int!, $limit: Int, $offset: Int) { authorFollowers(author_id: $author_id, limit: $limit) { id slug userpic name } }", + "query": '''query LoadAuthors($author_id: Int!, $limit: Int, $offset: Int) { + authorFollowers(author_id: $author_id, limit: $limit) { + id slug userpic name + } + }''', "operation": "LoadAuthors", "variables": {"author_id": author_id, "limit": amount}, } @@ -75,5 +83,6 @@ async def get_followers(author_id, amount): r = response.json() followers = r.get("data", {}).get("authorFollowers", []) except Exception as e: + print(e) followers = [] return followers diff --git a/services/presence.py b/services/presence.py index 11856ca..e35c177 100644 --- a/services/presence.py +++ b/services/presence.py @@ -1,6 +1,6 @@ import json from services.redis import redis -from validators.chat import Message +from validators.inbox import Message async def notify_message(message: Message, chat_id: str): diff --git a/setup.cfg b/setup.cfg deleted file mode 100755 index 588918a..0000000 --- a/setup.cfg +++ /dev/null @@ -1,39 +0,0 @@ -[isort] -# https://github.com/PyCQA/isort -line_length = 120 -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -force_alphabetical_sort = false - -[tool:brunette] -# https://github.com/odwyersoftware/brunette -line-length = 120 -single-quotes = false - -[flake8] -# https://github.com/PyCQA/flake8 -exclude = .git,__pycache__,.mypy_cache,.vercel -max-line-length = 120 -max-complexity = 15 -select = B,C,E,F,W,T4,B9 -# E203: Whitespace before ':' -# E266: Too many leading '#' for block comment -# E501: Line too long (82 > 79 characters) -# E722: Do not use bare except, specify exception instead -# W503: Line break occurred before a binary operator -# F403: 'from module import *' used; unable to detect undefined names -# C901: Function is too complex -ignore = E203,E266,E501,E722,W503,F403,C901 - -[mypy] -# https://github.com/python/mypy -ignore_missing_imports = true -warn_return_any = false -warn_unused_configs = true -disallow_untyped_calls = true -disallow_untyped_defs = true -disallow_incomplete_defs = true -[mypy-api.*] -ignore_errors = true diff --git a/validators/chat.py b/validators/inbox.py similarity index 100% rename from validators/chat.py rename to validators/inbox.py