diff --git a/README.md b/README.md
index c69428a9..a0b778b2 100644
--- a/README.md
+++ b/README.md
@@ -24,10 +24,8 @@ apt install redis nginx
First, install Postgres. Then you'll need some data
```
-
-psql -U postgres
-> create database discoursio;
-> \q
+brew install postgres
+createdb discoursio
python server.py migrate
```
@@ -42,3 +40,7 @@ python3 server.py dev
Put the header 'Authorization' with token from signIn query or registerUser mutation.
+# How to debug Ackee
+
+Set ACKEE_TOKEN var
+
diff --git a/auth/authenticate.py b/auth/authenticate.py
index 95695604..242d2793 100644
--- a/auth/authenticate.py
+++ b/auth/authenticate.py
@@ -9,7 +9,7 @@ from auth.credentials import AuthCredentials, AuthUser
from services.auth.users import UserStorage
from settings import SESSION_TOKEN_HEADER
from auth.tokenstorage import SessionToken
-from base.exceptions import InvalidToken
+from base.exceptions import InvalidToken, OperationNotAllowed, Unauthorized
class JWTAuthenticate(AuthenticationBackend):
@@ -30,27 +30,26 @@ class JWTAuthenticate(AuthenticationBackend):
try:
if len(token.split('.')) > 1:
payload = await SessionToken.verify(token)
+ if payload is None:
+ return AuthCredentials(scopes=[]), AuthUser(user_id=None)
+ user = await UserStorage.get_user(payload.user_id)
+ if not user:
+ return AuthCredentials(scopes=[]), AuthUser(user_id=None)
+ scopes = await user.get_permission()
+ return (
+ AuthCredentials(
+ user_id=payload.user_id,
+ scopes=scopes,
+ logged_in=True
+ ),
+ user,
+ )
else:
InvalidToken("please try again")
except Exception as exc:
print("[auth.authenticate] session token verify error")
print(exc)
- return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser(
- user_id=None
- )
-
- if payload is None:
- return AuthCredentials(scopes=[]), AuthUser(user_id=None)
-
- user = await UserStorage.get_user(payload.user_id)
- if not user:
- return AuthCredentials(scopes=[]), AuthUser(user_id=None)
-
- scopes = await user.get_permission()
- return (
- AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True),
- user,
- )
+ return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser(user_id=None)
def login_required(func):
@@ -58,10 +57,9 @@ def login_required(func):
async def wrap(parent, info: GraphQLResolveInfo, *args, **kwargs):
# print('[auth.authenticate] login required for %r with info %r' % (func, info)) # debug only
auth: AuthCredentials = info.context["request"].auth
- if auth and auth.user_id:
- print(auth) # debug only
+ # print(auth)
if not auth.logged_in:
- return {"error": auth.error_message or "Please login"}
+ raise OperationNotAllowed(auth.error_message or "Please login")
return await func(parent, info, *args, **kwargs)
return wrap
@@ -73,9 +71,9 @@ def permission_required(resource, operation, func):
print('[auth.authenticate] permission_required for %r with info %r' % (func, info)) # debug only
auth: AuthCredentials = info.context["request"].auth
if not auth.logged_in:
- return {"error": auth.error_message or "Please login"}
+ raise Unauthorized(auth.error_message or "Please login")
- # TODO: add check permission logix
+ # TODO: add actual check permission logix here
return await func(parent, info, *args, **kwargs)
diff --git a/auth/credentials.py b/auth/credentials.py
index 401ae420..15738d16 100644
--- a/auth/credentials.py
+++ b/auth/credentials.py
@@ -2,7 +2,7 @@ from typing import List, Optional, Text
from pydantic import BaseModel
-from base.exceptions import OperationNotAllowed
+from base.exceptions import Unauthorized
class Permission(BaseModel):
@@ -17,11 +17,13 @@ class AuthCredentials(BaseModel):
@property
def is_admin(self):
+ # TODO: check admin logix
return True
async def permissions(self) -> List[Permission]:
if self.user_id is None:
- raise OperationNotAllowed("Please login first")
+ raise Unauthorized("Please login first")
+ # TODO: implement permissions logix
return NotImplemented()
diff --git a/auth/email.py b/auth/email.py
index c0e2286a..8a1f8dfd 100644
--- a/auth/email.py
+++ b/auth/email.py
@@ -10,13 +10,13 @@ lang_subject = {
}
-async def send_auth_email(user, token, lang="ru"):
+async def send_auth_email(user, token, template="email_confirmation", lang="ru"):
try:
to = "%s <%s>" % (user.name, user.email)
if lang not in ['ru', 'en']:
lang = 'ru'
subject = lang_subject.get(lang, lang_subject["en"])
- template = "email_confirmation_" + lang
+ template = template + "_" + lang
payload = {
"from": noreply,
"to": to,
diff --git a/auth/jwtcodec.py b/auth/jwtcodec.py
index c2feacd3..387df057 100644
--- a/auth/jwtcodec.py
+++ b/auth/jwtcodec.py
@@ -34,7 +34,7 @@ class JWTCodec:
issuer="discours"
)
r = TokenPayload(**payload)
- print('[auth.jwtcodec] debug payload %r' % r)
+ # print('[auth.jwtcodec] debug payload %r' % r)
return r
except jwt.InvalidIssuedAtError:
print('[auth.jwtcodec] invalid issued at: %r' % r)
diff --git a/auth/oauth.py b/auth/oauth.py
index 88950c8d..54b5f11a 100644
--- a/auth/oauth.py
+++ b/auth/oauth.py
@@ -2,7 +2,7 @@ from authlib.integrations.starlette_client import OAuth
from starlette.responses import RedirectResponse
from auth.identity import Identity
from auth.tokenstorage import TokenStorage
-from settings import OAUTH_CLIENTS
+from settings import OAUTH_CLIENTS, FRONTEND_URL
oauth = OAuth()
@@ -84,6 +84,6 @@ async def oauth_authorize(request):
}
user = Identity.oauth(user_input)
session_token = await TokenStorage.create_session(user)
- response = RedirectResponse(url="https://new.discours.io/confirm")
+ response = RedirectResponse(url=FRONTEND_URL + "/confirm")
response.set_cookie("token", session_token)
return response
diff --git a/base/redis.py b/base/redis.py
index 7468af0a..ccc3758a 100644
--- a/base/redis.py
+++ b/base/redis.py
@@ -12,6 +12,7 @@ class RedisCache:
if self._instance is not None:
return
self._instance = await from_url(self._uri, encoding="utf-8")
+ # print(self._instance)
async def disconnect(self):
if self._instance is None:
@@ -23,10 +24,11 @@ class RedisCache:
async def execute(self, command, *args, **kwargs):
while not self._instance:
await sleep(1)
- try:
- await self._instance.execute_command(command, *args, **kwargs)
- except Exception:
- pass
+ try:
+ print("[redis] " + command + ' ' + ' '.join(args))
+ return await self._instance.execute_command(command, *args, **kwargs)
+ except Exception:
+ pass
async def lrange(self, key, start, stop):
return await self._instance.lrange(key, start, stop)
diff --git a/migration/__init__.py b/migration/__init__.py
index 2d195e06..4a25931d 100644
--- a/migration/__init__.py
+++ b/migration/__init__.py
@@ -314,9 +314,6 @@ async def handle_auto():
async def main():
if len(sys.argv) > 1:
- cmd = sys.argv[1]
- if type(cmd) == str:
- print("[migration] command: " + cmd)
init_tables()
await handle_auto()
else:
diff --git a/migration/export.py b/migration/export.py
index 988ab35d..102cfb14 100644
--- a/migration/export.py
+++ b/migration/export.py
@@ -4,7 +4,7 @@ from datetime import datetime, timezone
import frontmatter
-from .extract import extract_html, prepare_html_body
+from .extract import extract_html, extract_media
from .utils import DateTimeEncoder
OLD_DATE = "2016-03-05 22:22:00.350000"
@@ -50,11 +50,12 @@ def export_mdx(r):
def export_body(shout, storage):
entry = storage["content_items"]["by_oid"][shout["oid"]]
if entry:
- shout["body"], media = prepare_html_body(entry) # prepare_md_body(entry)
+ body = extract_html(entry)
+ media = extract_media(entry)
+ shout["body"] = body # prepare_html_body(entry) # prepare_md_body(entry)
shout["media"] = media
export_mdx(shout)
print("[export] html for %s" % shout["slug"])
- body, _media = extract_html(entry)
open(contentDir + shout["slug"] + ".html", "w").write(body)
else:
raise Exception("no content_items entry found")
diff --git a/migration/extract.py b/migration/extract.py
index 4ea44d04..5dd7ccba 100644
--- a/migration/extract.py
+++ b/migration/extract.py
@@ -3,7 +3,8 @@ import os
import re
import uuid
-from .html2text import html2text
+from bs4 import BeautifulSoup
+
TOOLTIP_REGEX = r"(\/\/\/(.+)\/\/\/)"
contentDir = os.path.join(
@@ -258,47 +259,44 @@ def extract_md(body, oid=""):
return newbody
-def prepare_md_body(entry):
- # body modifications
- body = ""
+def extract_media(entry):
+ ''' normalized media extraction method '''
+ # media [ { title pic url body } ]}
kind = entry.get("type")
- addon = ""
- if kind == "Video":
- addon = ""
- for m in entry.get("media", []):
- if "youtubeId" in m:
- addon += "\n"
+ if not kind:
+ print(entry)
+ raise Exception("shout no layout")
+ media = []
+ for m in entry.get("media") or []:
+ # title
+ title = m.get("title", "").replace("\n", " ").replace(" ", " ")
+ artist = m.get("performer") or m.get("artist")
+ if artist:
+ title = artist + " - " + title
+
+ # pic
+ url = m.get("fileUrl") or m.get("url", "")
+ pic = ""
+ if m.get("thumborId"):
+ pic = cdn + "/unsafe/1600x/" + m["thumborId"]
+
+ # url
+ if not url:
+ if kind == "Image":
+ url = pic
+ elif "youtubeId" in m:
+ url = "https://youtube.com/?watch=" + m["youtubeId"]
elif "vimeoId" in m:
- addon += "\n"
- else:
- print("[extract] media is not supported")
- print(m)
- body = "import VideoPlayer from '$/components/Article/VideoPlayer'\n\n" + addon
-
- elif kind == "Music":
- addon = ""
- for m in entry.get("media", []):
- artist = m.get("performer")
- trackname = ""
- if artist:
- trackname += artist + " - "
- if "title" in m:
- trackname += m.get("title", "")
- addon += (
- '\n'
- )
- body = "import AudioPlayer from '$/components/Article/AudioPlayer'\n\n" + addon
-
- body_orig, media = extract_html(entry)
- if body_orig:
- body += extract_md(html2text(body_orig), entry["_id"])
- if not body:
- print("[extract] empty MDX body")
- return body, media
+ url = "https://vimeo.com/" + m["vimeoId"]
+ # body
+ body = m.get("body") or m.get("literatureBody") or ""
+ media.append({
+ "url": url,
+ "pic": pic,
+ "title": title,
+ "body": body
+ })
+ return media
def prepare_html_body(entry):
@@ -308,7 +306,7 @@ def prepare_html_body(entry):
addon = ""
if kind == "Video":
addon = ""
- for m in entry.get("media", []):
+ for m in entry.get("media") or []:
if "youtubeId" in m:
addon += '