server-cli-todo-cleanup
This commit is contained in:
parent
0ba5047ff9
commit
f13f40c89a
|
@ -14,7 +14,7 @@ email_templates = {"confirm_email" : "", "auth_email" : "", "reset_password_emai
|
||||||
|
|
||||||
def load_email_templates():
|
def load_email_templates():
|
||||||
for name in email_templates:
|
for name in email_templates:
|
||||||
filename = "auth/templates/%s.tmpl" % name # TODO: check path
|
filename = "auth/templates/%s.tmpl" % name
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
email_templates[name] = f.read()
|
email_templates[name] = f.read()
|
||||||
print("[auth.email] templates loaded")
|
print("[auth.email] templates loaded")
|
||||||
|
|
|
@ -25,5 +25,3 @@ class CreateUser(BaseModel):
|
||||||
# age: Optional[int]
|
# age: Optional[int]
|
||||||
# phone: Optional[Text]
|
# phone: Optional[Text]
|
||||||
password: Optional[Text]
|
password: Optional[Text]
|
||||||
|
|
||||||
# TODO: update validations
|
|
||||||
|
|
2
main.py
2
main.py
|
@ -40,7 +40,7 @@ async def shutdown():
|
||||||
await redis.disconnect()
|
await redis.disconnect()
|
||||||
|
|
||||||
routes = [
|
routes = [
|
||||||
Route("/oauth/{provider}", endpoint=oauth_login), # TODO: isolate auth microservice
|
Route("/oauth/{provider}", endpoint=oauth_login),
|
||||||
Route("/oauth_authorize", endpoint=oauth_authorize),
|
Route("/oauth_authorize", endpoint=oauth_authorize),
|
||||||
Route("/email_authorize", endpoint=email_authorize)
|
Route("/email_authorize", endpoint=email_authorize)
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,11 +9,11 @@ s3 = 'https://discours-io.s3.amazonaws.com/'
|
||||||
cdn = 'https://assets.discours.io'
|
cdn = 'https://assets.discours.io'
|
||||||
|
|
||||||
def replace_tooltips(body):
|
def replace_tooltips(body):
|
||||||
# FIXME: if you prefer regexp
|
# change if you prefer regexp
|
||||||
newbody = body
|
newbody = body
|
||||||
matches = list(re.finditer(TOOLTIP_REGEX, body, re.IGNORECASE | re.MULTILINE))[1:]
|
matches = list(re.finditer(TOOLTIP_REGEX, body, re.IGNORECASE | re.MULTILINE))[1:]
|
||||||
for match in matches:
|
for match in matches:
|
||||||
newbody = body.replace(match.group(1), '<Tooltip text="' + match.group(2) + '" />') # FIXME: doesn't work
|
newbody = body.replace(match.group(1), '<Tooltip text="' + match.group(2) + '" />') # NOTE: doesn't work
|
||||||
if len(matches) > 0:
|
if len(matches) > 0:
|
||||||
print('[extract] found %d tooltips' % len(matches))
|
print('[extract] found %d tooltips' % len(matches))
|
||||||
return newbody
|
return newbody
|
||||||
|
@ -54,7 +54,7 @@ cache = {}
|
||||||
|
|
||||||
|
|
||||||
def reextract_images(body, oid):
|
def reextract_images(body, oid):
|
||||||
# FIXME: if you prefer regexp
|
# change if you prefer regexp
|
||||||
matches = list(re.finditer(IMG_REGEX, body, re.IGNORECASE | re.MULTILINE))[1:]
|
matches = list(re.finditer(IMG_REGEX, body, re.IGNORECASE | re.MULTILINE))[1:]
|
||||||
i = 0
|
i = 0
|
||||||
for match in matches:
|
for match in matches:
|
||||||
|
@ -63,7 +63,7 @@ def reextract_images(body, oid):
|
||||||
name = oid + str(i)
|
name = oid + str(i)
|
||||||
link = public + '/upload/image-' + name + '.' + ext
|
link = public + '/upload/image-' + name + '.' + ext
|
||||||
img = match.group(4)
|
img = match.group(4)
|
||||||
title = match.group(1) # FIXME: this is not the title
|
title = match.group(1) # NOTE: this is not the title
|
||||||
if img not in cache:
|
if img not in cache:
|
||||||
content = base64.b64decode(img + '==')
|
content = base64.b64decode(img + '==')
|
||||||
print(str(len(img)) + ' image bytes been written')
|
print(str(len(img)) + ' image bytes been written')
|
||||||
|
@ -72,7 +72,7 @@ def reextract_images(body, oid):
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
print('[extract] image cached ' + cache[img])
|
print('[extract] image cached ' + cache[img])
|
||||||
body.replace(str(match), '') # FIXME: this does not work
|
body.replace(str(match), '') # WARNING: this does not work
|
||||||
return body
|
return body
|
||||||
|
|
||||||
IMAGES = {
|
IMAGES = {
|
||||||
|
|
|
@ -30,8 +30,7 @@ from .utils import (
|
||||||
__version__ = (2020, 1, 16)
|
__version__ = (2020, 1, 16)
|
||||||
|
|
||||||
|
|
||||||
# TODO:
|
# TODO: Support decoded entities with UNIFIABLE.
|
||||||
# Support decoded entities with UNIFIABLE.
|
|
||||||
|
|
||||||
|
|
||||||
class HTML2Text(html.parser.HTMLParser):
|
class HTML2Text(html.parser.HTMLParser):
|
||||||
|
@ -503,7 +502,7 @@ class HTML2Text(html.parser.HTMLParser):
|
||||||
self.handle_emphasis(start, tag_style, parent_style)
|
self.handle_emphasis(start, tag_style, parent_style)
|
||||||
|
|
||||||
if tag in ["kbd", "code", "tt"] and not self.pre:
|
if tag in ["kbd", "code", "tt"] and not self.pre:
|
||||||
self.o("`") # TODO: `` `this` ``
|
self.o("`") # `` `this` ``
|
||||||
self.code = not self.code
|
self.code = not self.code
|
||||||
|
|
||||||
if tag == "abbr":
|
if tag == "abbr":
|
||||||
|
@ -681,7 +680,7 @@ class HTML2Text(html.parser.HTMLParser):
|
||||||
# Indent two spaces per list, except use three spaces for an
|
# Indent two spaces per list, except use three spaces for an
|
||||||
# unordered list inside an ordered list.
|
# unordered list inside an ordered list.
|
||||||
# https://spec.commonmark.org/0.28/#motivation
|
# https://spec.commonmark.org/0.28/#motivation
|
||||||
# TODO: line up <ol><li>s > 9 correctly.
|
# WARNING: does not line up <ol><li>s > 9 correctly.
|
||||||
parent_list = None
|
parent_list = None
|
||||||
for list in self.list:
|
for list in self.list:
|
||||||
self.o(
|
self.o(
|
||||||
|
@ -761,7 +760,6 @@ class HTML2Text(html.parser.HTMLParser):
|
||||||
self.out("\n[/code]")
|
self.out("\n[/code]")
|
||||||
self.p()
|
self.p()
|
||||||
|
|
||||||
# TODO: Add docstring for these one letter functions
|
|
||||||
def pbr(self) -> None:
|
def pbr(self) -> None:
|
||||||
"Pretty print has a line break"
|
"Pretty print has a line break"
|
||||||
if self.p_p == 0:
|
if self.p_p == 0:
|
||||||
|
@ -807,7 +805,7 @@ class HTML2Text(html.parser.HTMLParser):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.startpre:
|
if self.startpre:
|
||||||
# self.out(" :") #TODO: not output when already one there
|
# self.out(" :") # not an output when already one there
|
||||||
if not data.startswith("\n") and not data.startswith("\r\n"):
|
if not data.startswith("\n") and not data.startswith("\r\n"):
|
||||||
# <pre>stuff...
|
# <pre>stuff...
|
||||||
data = "\n" + data
|
data = "\n" + data
|
||||||
|
|
|
@ -47,8 +47,8 @@ def migrate(entry, storage):
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
reaction_dict = {}
|
reaction_dict = {}
|
||||||
# FIXME: comment_dict['createdAt'] = ts if not entry.get('createdAt') else date_parse(entry.get('createdAt'))
|
reaction_dict['createdAt'] = ts if not entry.get('createdAt') else date_parse(entry.get('createdAt'))
|
||||||
# print('[migration] comment original date %r' % entry.get('createdAt'))
|
print('[migration] reaction original date %r' % entry.get('createdAt'))
|
||||||
# print('[migration] comment date %r ' % comment_dict['createdAt'])
|
# print('[migration] comment date %r ' % comment_dict['createdAt'])
|
||||||
reaction_dict['body'] = html2text(entry.get('body', ''))
|
reaction_dict['body'] = html2text(entry.get('body', ''))
|
||||||
reaction_dict['oid'] = entry['_id']
|
reaction_dict['oid'] = entry['_id']
|
||||||
|
|
|
@ -118,8 +118,8 @@ def migrate(entry, storage):
|
||||||
s = object()
|
s = object()
|
||||||
shout_dict = r.copy()
|
shout_dict = r.copy()
|
||||||
user = None
|
user = None
|
||||||
del shout_dict['topics'] # FIXME: AttributeError: 'str' object has no attribute '_sa_instance_state'
|
del shout_dict['topics'] # NOTE: AttributeError: 'str' object has no attribute '_sa_instance_state'
|
||||||
#del shout_dict['rating'] # FIXME: TypeError: 'rating' is an invalid keyword argument for Shout
|
#del shout_dict['rating'] # NOTE: TypeError: 'rating' is an invalid keyword argument for Shout
|
||||||
#del shout_dict['ratings']
|
#del shout_dict['ratings']
|
||||||
email = userdata.get('email')
|
email = userdata.get('email')
|
||||||
slug = userdata.get('slug')
|
slug = userdata.get('slug')
|
||||||
|
|
|
@ -17,4 +17,6 @@ class Collection(Base):
|
||||||
title: str = Column(String, nullable=False, comment="Title")
|
title: str = Column(String, nullable=False, comment="Title")
|
||||||
body: str = Column(String, nullable=True, comment="Body")
|
body: str = Column(String, nullable=True, comment="Body")
|
||||||
pic: str = Column(String, nullable=True, comment="Picture")
|
pic: str = Column(String, nullable=True, comment="Picture")
|
||||||
|
createdAt: datetime = Column(DateTime, default=datetime.now, comment="Created At")
|
||||||
|
createdBy: str = Column(ForeignKey('user.id'), comment="Created By")
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,4 @@ class Notification(Base):
|
||||||
template: str = Column(String, nullable = False)
|
template: str = Column(String, nullable = False)
|
||||||
variables: JSONType = Column(JSONType, nullable = True) # [ <var1>, .. ]
|
variables: JSONType = Column(JSONType, nullable = True) # [ <var1>, .. ]
|
||||||
|
|
||||||
# FIXME looks like frontend code
|
# looks like frontend code
|
80
resolvers/collection.py
Normal file
80
resolvers/collection.py
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
from orm.collection import Collection, CollectionFollower
|
||||||
|
from base.orm import local_session
|
||||||
|
from orm.user import User
|
||||||
|
from base.resolvers import mutation, query
|
||||||
|
from auth.authenticate import login_required
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Collection, List
|
||||||
|
from sqlalchemy import and_
|
||||||
|
|
||||||
|
@mutation.field("createCollection")
|
||||||
|
@login_required
|
||||||
|
async def create_collection(_, info, input):
|
||||||
|
auth = info.context["request"].auth
|
||||||
|
user_id = auth.user_id
|
||||||
|
collection = Collection.create(
|
||||||
|
slug = input.get('slug', ''),
|
||||||
|
title = input.get('title', ''),
|
||||||
|
desc = input.get('desc', ''),
|
||||||
|
pic = input.get('pic', '')
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"collection": collection}
|
||||||
|
|
||||||
|
@mutation.field("updateCollection")
|
||||||
|
@login_required
|
||||||
|
async def update_collection(_, info, input):
|
||||||
|
auth = info.context["request"].auth
|
||||||
|
user_id = auth.user_id
|
||||||
|
collection_slug = input.get('slug', '')
|
||||||
|
with local_session() as session:
|
||||||
|
owner = session.query(User).filter(User.id == user_id) # note list here
|
||||||
|
collection = session.query(Collection).filter(Collection.slug == collection_slug).first()
|
||||||
|
editors = [e.slug for e in collection.editors]
|
||||||
|
if not collection:
|
||||||
|
return {"error": "invalid collection id"}
|
||||||
|
if collection.createdBy not in (owner + editors):
|
||||||
|
return {"error": "access denied"}
|
||||||
|
collection.title = input.get('title', '')
|
||||||
|
collection.desc = input.get('desc', '')
|
||||||
|
collection.pic = input.get('pic', '')
|
||||||
|
collection.updatedAt = datetime.now()
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
@mutation.field("deleteCollection")
|
||||||
|
@login_required
|
||||||
|
async def delete_collection(_, info, slug):
|
||||||
|
auth = info.context["request"].auth
|
||||||
|
user_id = auth.user_id
|
||||||
|
with local_session() as session:
|
||||||
|
collection = session.query(Collection).filter(Collection.slug == slug).first()
|
||||||
|
if not collection:
|
||||||
|
return {"error": "invalid collection slug"}
|
||||||
|
if collection.owner != user_id:
|
||||||
|
return {"error": "access denied"}
|
||||||
|
collection.deletedAt = datetime.now()
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
@query.field("getCollection")
|
||||||
|
async def get_collection(_, info, userslug, colslug):
|
||||||
|
with local_session() as session:
|
||||||
|
user = session.query(User).filter(User.slug == userslug).first()
|
||||||
|
if user:
|
||||||
|
collection = session.\
|
||||||
|
query(Collection).\
|
||||||
|
where(and_(Collection.createdBy == user.id, Collection.slug == colslug)).\
|
||||||
|
first()
|
||||||
|
if not collection:
|
||||||
|
return {"error": "collection not found"}
|
||||||
|
return collection
|
||||||
|
|
||||||
|
@query.field("getMyColelctions")
|
||||||
|
@login_required
|
||||||
|
async def get_collections(_, info):
|
||||||
|
auth = info.context["request"].auth
|
||||||
|
user_id = auth.user_id
|
||||||
|
with local_session() as session:
|
||||||
|
collections = session.query(Collection).when(Collection.createdBy == user_id).all()
|
||||||
|
return collections
|
|
@ -75,7 +75,7 @@ async def update_reaction(_, info, inp):
|
||||||
reaction.body = inp['body']
|
reaction.body = inp['body']
|
||||||
reaction.updatedAt = datetime.now()
|
reaction.updatedAt = datetime.now()
|
||||||
if reaction.kind != inp['kind']:
|
if reaction.kind != inp['kind']:
|
||||||
# TODO: change mind detection
|
# NOTE: change mind detection can be here
|
||||||
pass
|
pass
|
||||||
if inp.get('range'):
|
if inp.get('range'):
|
||||||
reaction.range = inp.get('range')
|
reaction.range = inp.get('range')
|
||||||
|
|
|
@ -51,7 +51,7 @@ async def view_shout(_, info, slug):
|
||||||
@query.field("getShoutBySlug")
|
@query.field("getShoutBySlug")
|
||||||
async def get_shout_by_slug(_, info, slug):
|
async def get_shout_by_slug(_, info, slug):
|
||||||
shout = None
|
shout = None
|
||||||
# TODO: append captions anyhow
|
# FIXME: append captions anyhow
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
shout = session.query(Shout).\
|
shout = session.query(Shout).\
|
||||||
options([
|
options([
|
||||||
|
@ -65,7 +65,7 @@ async def get_shout_by_slug(_, info, slug):
|
||||||
|
|
||||||
if not shout:
|
if not shout:
|
||||||
print(f"[resolvers.zine] error: shout with slug {slug} not exist")
|
print(f"[resolvers.zine] error: shout with slug {slug} not exist")
|
||||||
return {} #TODO return error field
|
return {"error" : "shout not found"}
|
||||||
|
|
||||||
return shout
|
return shout
|
||||||
|
|
||||||
|
|
|
@ -189,9 +189,6 @@ type Mutation {
|
||||||
unfollow(what: FollowingEntity!, slug: String!): Result!
|
unfollow(what: FollowingEntity!, slug: String!): Result!
|
||||||
|
|
||||||
# TODO: transform reaction with body to shout
|
# TODO: transform reaction with body to shout
|
||||||
|
|
||||||
# NOTE: so-named 'collections' are tuned feeds
|
|
||||||
# TODO: Feed entity and CRUM: createFeed updateFeed deleteFeed mergeFeeds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
################################### Query
|
################################### Query
|
||||||
|
@ -229,7 +226,7 @@ type Query {
|
||||||
shoutsByCommunities(slugs: [String]!, page: Int!, size: Int!): [Shout]!
|
shoutsByCommunities(slugs: [String]!, page: Int!, size: Int!): [Shout]!
|
||||||
myCandidates(page: Int!, size: Int!): [Shout]! # test
|
myCandidates(page: Int!, size: Int!): [Shout]! # test
|
||||||
topViewed(page: Int!, size: Int!): [Shout]!
|
topViewed(page: Int!, size: Int!): [Shout]!
|
||||||
# TODO: topReacted(page: Int!, size: Int!): [Shout]!
|
# topReacted(page: Int!, size: Int!): [Shout]!
|
||||||
topMonth(page: Int!, size: Int!): [Shout]!
|
topMonth(page: Int!, size: Int!): [Shout]!
|
||||||
topOverall(page: Int!, size: Int!): [Shout]!
|
topOverall(page: Int!, size: Int!): [Shout]!
|
||||||
recentPublished(page: Int!, size: Int!): [Shout]! # homepage
|
recentPublished(page: Int!, size: Int!): [Shout]! # homepage
|
||||||
|
|
|
@ -4,7 +4,8 @@ from settings import PORT
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
x = sys.argv[1] or ""
|
x = ''
|
||||||
|
if len(sys.argv) > 1: x = sys.argv[1]
|
||||||
if x == "dev":
|
if x == "dev":
|
||||||
print("DEV MODE")
|
print("DEV MODE")
|
||||||
headers = [
|
headers = [
|
||||||
|
|
|
@ -12,7 +12,6 @@ class UserStorage:
|
||||||
self = UserStorage
|
self = UserStorage
|
||||||
users = session.query(User).\
|
users = session.query(User).\
|
||||||
options(selectinload(User.roles), selectinload(User.ratings)).all()
|
options(selectinload(User.roles), selectinload(User.ratings)).all()
|
||||||
# TODO: add shouts and reactions counters
|
|
||||||
self.users = dict([(user.id, user) for user in users])
|
self.users = dict([(user.id, user) for user in users])
|
||||||
print('[service.auth] %d users' % len(self.users))
|
print('[service.auth] %d users' % len(self.users))
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ class ReactedStorage:
|
||||||
self.this_day_reactions[shout] = reaction
|
self.this_day_reactions[shout] = reaction
|
||||||
|
|
||||||
print('[service.reacted] watching %d shouts' % len(reactions))
|
print('[service.reacted] watching %d shouts' % len(reactions))
|
||||||
# TODO: add reactions ?
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_shout(shout_slug):
|
async def get_shout(shout_slug):
|
||||||
|
|
|
@ -17,7 +17,6 @@ class ViewedByDay(Base):
|
||||||
class ViewedStorage:
|
class ViewedStorage:
|
||||||
viewed = {
|
viewed = {
|
||||||
'shouts': {},
|
'shouts': {},
|
||||||
# TODO: ? 'reactions': {},
|
|
||||||
'topics': {} # TODO: get sum views for all shouts in topic
|
'topics': {} # TODO: get sum views for all shouts in topic
|
||||||
}
|
}
|
||||||
this_day_views = {}
|
this_day_views = {}
|
||||||
|
@ -43,7 +42,6 @@ class ViewedStorage:
|
||||||
self.this_day_views[shout] = view
|
self.this_day_views[shout] = view
|
||||||
|
|
||||||
print('[service.viewed] watching %d shouts' % len(views))
|
print('[service.viewed] watching %d shouts' % len(views))
|
||||||
# TODO: add reactions ?
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_shout(shout_slug):
|
async def get_shout(shout_slug):
|
||||||
|
|
|
@ -20,7 +20,8 @@ class ShoutAuthorStorage:
|
||||||
self.authors_by_shout[shout].append(user)
|
self.authors_by_shout[shout].append(user)
|
||||||
else:
|
else:
|
||||||
self.authors_by_shout[shout] = [user]
|
self.authors_by_shout[shout] = [user]
|
||||||
print('[service.shoutauthor] %d shouts ' % len(self.authors_by_shout))
|
print('[service.shoutauthor] %d authors ' % len(self.authors_by_shout))
|
||||||
|
# FIXME: [service.shoutauthor] 4251 authors
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_authors(shout):
|
async def get_authors(shout):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user