nochecks
This commit is contained in:
parent
57e1460356
commit
47b285f8ac
2
main.py
2
main.py
|
@ -8,6 +8,7 @@ from starlette.middleware import Middleware
|
||||||
from starlette.middleware.authentication import AuthenticationMiddleware
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
||||||
from starlette.middleware.sessions import SessionMiddleware
|
from starlette.middleware.sessions import SessionMiddleware
|
||||||
from starlette.routing import Route
|
from starlette.routing import Route
|
||||||
|
from orm import init_tables
|
||||||
|
|
||||||
from auth.authenticate import JWTAuthenticate
|
from auth.authenticate import JWTAuthenticate
|
||||||
from auth.oauth import oauth_login, oauth_authorize
|
from auth.oauth import oauth_login, oauth_authorize
|
||||||
|
@ -30,6 +31,7 @@ middleware = [
|
||||||
|
|
||||||
|
|
||||||
async def start_up():
|
async def start_up():
|
||||||
|
init_tables()
|
||||||
await redis.connect()
|
await redis.connect()
|
||||||
await storages_init()
|
await storages_init()
|
||||||
views_stat_task = asyncio.create_task(ViewedStorage().worker())
|
views_stat_task = asyncio.create_task(ViewedStorage().worker())
|
||||||
|
|
|
@ -7,7 +7,6 @@ import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import bs4
|
import bs4
|
||||||
from base.redis import redis
|
|
||||||
from migration.tables.comments import migrate as migrateComment
|
from migration.tables.comments import migrate as migrateComment
|
||||||
from migration.tables.comments import migrate_2stage as migrateComment_2stage
|
from migration.tables.comments import migrate_2stage as migrateComment_2stage
|
||||||
from migration.tables.content_items import get_shout_slug
|
from migration.tables.content_items import get_shout_slug
|
||||||
|
@ -17,6 +16,7 @@ from migration.tables.users import migrate as migrateUser
|
||||||
from migration.tables.users import migrate_2stage as migrateUser_2stage
|
from migration.tables.users import migrate_2stage as migrateUser_2stage
|
||||||
from orm.reaction import Reaction
|
from orm.reaction import Reaction
|
||||||
from settings import DB_URL
|
from settings import DB_URL
|
||||||
|
from orm import init_tables
|
||||||
|
|
||||||
# from export import export_email_subscriptions
|
# from export import export_email_subscriptions
|
||||||
from .export import export_mdx, export_slug
|
from .export import export_mdx, export_slug
|
||||||
|
@ -84,6 +84,7 @@ async def shouts_handle(storage, args):
|
||||||
discours_author = 0
|
discours_author = 0
|
||||||
anonymous_author = 0
|
anonymous_author = 0
|
||||||
pub_counter = 0
|
pub_counter = 0
|
||||||
|
ignored = 0
|
||||||
topics_dataset_bodies = []
|
topics_dataset_bodies = []
|
||||||
topics_dataset_tlist = []
|
topics_dataset_tlist = []
|
||||||
for entry in storage["shouts"]["data"]:
|
for entry in storage["shouts"]["data"]:
|
||||||
|
@ -96,6 +97,7 @@ async def shouts_handle(storage, args):
|
||||||
|
|
||||||
# migrate
|
# migrate
|
||||||
shout = await migrateShout(entry, storage)
|
shout = await migrateShout(entry, storage)
|
||||||
|
if shout:
|
||||||
storage["shouts"]["by_oid"][entry["_id"]] = shout
|
storage["shouts"]["by_oid"][entry["_id"]] = shout
|
||||||
storage["shouts"]["by_slug"][shout["slug"]] = shout
|
storage["shouts"]["by_slug"][shout["slug"]] = shout
|
||||||
# shouts.topics
|
# shouts.topics
|
||||||
|
@ -125,11 +127,14 @@ async def shouts_handle(storage, args):
|
||||||
texts = texts + b.findAll(text=True)
|
texts = texts + b.findAll(text=True)
|
||||||
topics_dataset_bodies.append(" ".join([x.strip().lower() for x in texts]))
|
topics_dataset_bodies.append(" ".join([x.strip().lower() for x in texts]))
|
||||||
topics_dataset_tlist.append(shout["topics"])
|
topics_dataset_tlist.append(shout["topics"])
|
||||||
|
else:
|
||||||
|
ignored += 1
|
||||||
|
|
||||||
# np.savetxt('topics_dataset.csv', (topics_dataset_bodies, topics_dataset_tlist), delimiter=',
|
# np.savetxt('topics_dataset.csv', (topics_dataset_bodies, topics_dataset_tlist), delimiter=',
|
||||||
# ', fmt='%s')
|
# ', fmt='%s')
|
||||||
|
|
||||||
print("[migration] " + str(counter) + " content items were migrated")
|
print("[migration] " + str(counter) + " content items were migrated")
|
||||||
|
print("[migration] " + str(ignored) + " content items were ignored")
|
||||||
print("[migration] " + str(pub_counter) + " have been published")
|
print("[migration] " + str(pub_counter) + " have been published")
|
||||||
print("[migration] " + str(discours_author) + " authored by @discours")
|
print("[migration] " + str(discours_author) + " authored by @discours")
|
||||||
print("[migration] " + str(anonymous_author) + " authored by @anonymous")
|
print("[migration] " + str(anonymous_author) + " authored by @anonymous")
|
||||||
|
@ -182,8 +187,6 @@ async def all_handle(storage, args):
|
||||||
await users_handle(storage)
|
await users_handle(storage)
|
||||||
await topics_handle(storage)
|
await topics_handle(storage)
|
||||||
print("[migration] users and topics are migrated")
|
print("[migration] users and topics are migrated")
|
||||||
await redis.connect()
|
|
||||||
print("[migration] redis connected")
|
|
||||||
await shouts_handle(storage, args)
|
await shouts_handle(storage, args)
|
||||||
print("[migration] migrating comments")
|
print("[migration] migrating comments")
|
||||||
await comments_handle(storage)
|
await comments_handle(storage)
|
||||||
|
@ -314,6 +317,7 @@ async def main():
|
||||||
cmd = sys.argv[1]
|
cmd = sys.argv[1]
|
||||||
if type(cmd) == str:
|
if type(cmd) == str:
|
||||||
print("[migration] command: " + cmd)
|
print("[migration] command: " + cmd)
|
||||||
|
init_tables()
|
||||||
await handle_auto()
|
await handle_auto()
|
||||||
else:
|
else:
|
||||||
print("[migration] usage: python server.py migrate")
|
print("[migration] usage: python server.py migrate")
|
||||||
|
|
|
@ -3,10 +3,8 @@ import json
|
||||||
from dateutil.parser import parse as date_parse
|
from dateutil.parser import parse as date_parse
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from transliterate import translit
|
from transliterate import translit
|
||||||
|
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from migration.extract import prepare_html_body
|
from migration.extract import prepare_html_body
|
||||||
from orm.community import Community
|
|
||||||
from orm.reaction import Reaction, ReactionKind
|
from orm.reaction import Reaction, ReactionKind
|
||||||
from orm.shout import Shout, ShoutTopic, ShoutReactionsFollower
|
from orm.shout import Shout, ShoutTopic, ShoutReactionsFollower
|
||||||
from orm.user import User
|
from orm.user import User
|
||||||
|
@ -103,12 +101,8 @@ async def migrate(entry, storage):
|
||||||
r = {
|
r = {
|
||||||
"layout": type2layout[entry["type"]],
|
"layout": type2layout[entry["type"]],
|
||||||
"title": entry["title"],
|
"title": entry["title"],
|
||||||
"community": Community.default_community.id,
|
|
||||||
"authors": [],
|
"authors": [],
|
||||||
"topics": set([]),
|
"topics": set([])
|
||||||
# 'rating': 0,
|
|
||||||
# 'ratings': [],
|
|
||||||
"createdAt": [],
|
|
||||||
}
|
}
|
||||||
topics_by_oid = storage["topics"]["by_oid"]
|
topics_by_oid = storage["topics"]["by_oid"]
|
||||||
users_by_oid = storage["users"]["by_oid"]
|
users_by_oid = storage["users"]["by_oid"]
|
||||||
|
@ -177,6 +171,7 @@ async def migrate(entry, storage):
|
||||||
# add author as TopicFollower
|
# add author as TopicFollower
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
for tpc in r['topics']:
|
for tpc in r['topics']:
|
||||||
|
try:
|
||||||
tf = session.query(
|
tf = session.query(
|
||||||
TopicFollower
|
TopicFollower
|
||||||
).where(
|
).where(
|
||||||
|
@ -191,6 +186,9 @@ async def migrate(entry, storage):
|
||||||
auto=True
|
auto=True
|
||||||
)
|
)
|
||||||
session.add(tf)
|
session.add(tf)
|
||||||
|
except IntegrityError:
|
||||||
|
print('[migration.shout] skipped by topic ' + tpc)
|
||||||
|
return
|
||||||
|
|
||||||
entry["topics"] = r["topics"]
|
entry["topics"] = r["topics"]
|
||||||
entry["cover"] = r["cover"]
|
entry["cover"] = r["cover"]
|
||||||
|
@ -205,7 +203,6 @@ async def migrate(entry, storage):
|
||||||
user = None
|
user = None
|
||||||
del shout_dict["topics"]
|
del shout_dict["topics"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
# c = session.query(Community).all().pop()
|
|
||||||
if not user and userslug:
|
if not user and userslug:
|
||||||
user = session.query(User).filter(User.slug == userslug).first()
|
user = session.query(User).filter(User.slug == userslug).first()
|
||||||
if not user and userdata:
|
if not user and userdata:
|
||||||
|
|
|
@ -200,7 +200,6 @@
|
||||||
"ecology": "ecology",
|
"ecology": "ecology",
|
||||||
"economics": "economics",
|
"economics": "economics",
|
||||||
"eda": "food",
|
"eda": "food",
|
||||||
"editing": "editing",
|
|
||||||
"editorial-statements": "editorial-statements",
|
"editorial-statements": "editorial-statements",
|
||||||
"eduard-limonov": "eduard-limonov",
|
"eduard-limonov": "eduard-limonov",
|
||||||
"education": "education",
|
"education": "education",
|
||||||
|
@ -597,7 +596,6 @@
|
||||||
"r-b": "rnb",
|
"r-b": "rnb",
|
||||||
"rasizm": "racism",
|
"rasizm": "racism",
|
||||||
"realizm": "realism",
|
"realizm": "realism",
|
||||||
"redaktura": "editorial",
|
|
||||||
"refleksiya": "reflection",
|
"refleksiya": "reflection",
|
||||||
"reggi": "reggae",
|
"reggi": "reggae",
|
||||||
"religion": "religion",
|
"religion": "religion",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from migration.extract import extract_md, html2text
|
from migration.extract import extract_md, html2text
|
||||||
from orm import Topic, Community
|
from orm import Topic
|
||||||
|
|
||||||
|
|
||||||
def migrate(entry):
|
def migrate(entry):
|
||||||
|
@ -8,9 +8,7 @@ def migrate(entry):
|
||||||
topic_dict = {
|
topic_dict = {
|
||||||
"slug": entry["slug"],
|
"slug": entry["slug"],
|
||||||
"oid": entry["_id"],
|
"oid": entry["_id"],
|
||||||
"title": entry["title"].replace(" ", " "),
|
"title": entry["title"].replace(" ", " ")
|
||||||
"children": [],
|
|
||||||
"community": Community.default_community.slug,
|
|
||||||
}
|
}
|
||||||
topic_dict["body"] = extract_md(html2text(body_orig), entry["_id"])
|
topic_dict["body"] = extract_md(html2text(body_orig), entry["_id"])
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
|
|
@ -36,6 +36,7 @@ def migrate(entry):
|
||||||
)
|
)
|
||||||
bio = BeautifulSoup(entry.get("profile").get("bio") or "", features="lxml").text
|
bio = BeautifulSoup(entry.get("profile").get("bio") or "", features="lxml").text
|
||||||
if bio.startswith('<'):
|
if bio.startswith('<'):
|
||||||
|
print('[migration] bio! ' + bio)
|
||||||
bio = BeautifulSoup(bio, features="lxml").text
|
bio = BeautifulSoup(bio, features="lxml").text
|
||||||
bio = bio.replace('\(', '(').replace('\)', ')')
|
bio = bio.replace('\(', '(').replace('\)', ')')
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ from orm.reaction import Reaction
|
||||||
from orm.shout import Shout
|
from orm.shout import Shout
|
||||||
from orm.topic import Topic, TopicFollower
|
from orm.topic import Topic, TopicFollower
|
||||||
from orm.user import User, UserRating
|
from orm.user import User, UserRating
|
||||||
|
from orm.viewed import ViewedEntry
|
||||||
|
|
||||||
|
# NOTE: keep orm module isolated
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"User",
|
"User",
|
||||||
|
@ -19,13 +22,18 @@ __all__ = [
|
||||||
"Notification",
|
"Notification",
|
||||||
"Reaction",
|
"Reaction",
|
||||||
"UserRating"
|
"UserRating"
|
||||||
|
"ViewedEntry"
|
||||||
]
|
]
|
||||||
|
|
||||||
Base.metadata.create_all(engine)
|
|
||||||
Operation.init_table()
|
|
||||||
Resource.init_table()
|
|
||||||
User.init_table()
|
|
||||||
Community.init_table()
|
|
||||||
Role.init_table()
|
|
||||||
|
|
||||||
# NOTE: keep orm module isolated
|
def init_tables():
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
Operation.init_table()
|
||||||
|
Resource.init_table()
|
||||||
|
User.init_table()
|
||||||
|
Community.init_table()
|
||||||
|
UserRating.init_table()
|
||||||
|
Shout.init_table()
|
||||||
|
Role.init_table()
|
||||||
|
ViewedEntry.init_table()
|
||||||
|
print("[orm] tables initialized")
|
||||||
|
|
|
@ -32,12 +32,14 @@ class Community(Base):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def init_table():
|
def init_table():
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
default = (
|
d = (
|
||||||
session.query(Community).filter(Community.slug == "discours").first()
|
session.query(Community).filter(Community.slug == "discours").first()
|
||||||
)
|
)
|
||||||
if not default:
|
if not d:
|
||||||
default = Community.create(
|
d = Community.create(
|
||||||
name="Дискурс", slug="discours", createdBy="discours"
|
name="Дискурс", slug="discours", createdBy="anonymous"
|
||||||
)
|
)
|
||||||
|
session.add(d)
|
||||||
Community.default_community = default
|
session.commit()
|
||||||
|
Community.default_community = d
|
||||||
|
print('[migration] default community: %s' % d.id)
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Role(Base):
|
||||||
default = Role.create(
|
default = Role.create(
|
||||||
name="author",
|
name="author",
|
||||||
desc="Role for author",
|
desc="Role for author",
|
||||||
community=Community.default_community.id,
|
community=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
Role.default_role = default
|
Role.default_role = default
|
||||||
|
|
20
orm/shout.py
20
orm/shout.py
|
@ -1,9 +1,9 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, JSON
|
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, String, JSON
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from base.orm import Base
|
from base.orm import Base, local_session
|
||||||
from orm.reaction import Reaction
|
from orm.reaction import Reaction
|
||||||
from orm.topic import Topic
|
from orm.topic import Topic
|
||||||
from orm.user import User
|
from orm.user import User
|
||||||
|
@ -43,7 +43,7 @@ class Shout(Base):
|
||||||
__tablename__ = "shout"
|
__tablename__ = "shout"
|
||||||
|
|
||||||
slug = Column(String, unique=True)
|
slug = Column(String, unique=True)
|
||||||
community = Column(Integer, ForeignKey("community.id"), nullable=False, comment="Community")
|
community = Column(ForeignKey("community.id"), default=1)
|
||||||
lang = Column(String, nullable=False, default='ru', comment="Language")
|
lang = Column(String, nullable=False, default='ru', comment="Language")
|
||||||
body = Column(String, nullable=False, comment="Body")
|
body = Column(String, nullable=False, comment="Body")
|
||||||
title = Column(String, nullable=True)
|
title = Column(String, nullable=True)
|
||||||
|
@ -56,7 +56,6 @@ class Shout(Base):
|
||||||
reactions = relationship(lambda: Reaction)
|
reactions = relationship(lambda: Reaction)
|
||||||
visibility = Column(String, nullable=True) # owner authors community public
|
visibility = Column(String, nullable=True) # owner authors community public
|
||||||
versionOf = Column(ForeignKey("shout.slug"), nullable=True)
|
versionOf = Column(ForeignKey("shout.slug"), nullable=True)
|
||||||
lang = Column(String, default='ru')
|
|
||||||
oid = Column(String, nullable=True)
|
oid = Column(String, nullable=True)
|
||||||
media = Column(JSON, nullable=True)
|
media = Column(JSON, nullable=True)
|
||||||
|
|
||||||
|
@ -64,3 +63,16 @@ class Shout(Base):
|
||||||
updatedAt = Column(DateTime, nullable=True, comment="Updated at")
|
updatedAt = Column(DateTime, nullable=True, comment="Updated at")
|
||||||
publishedAt = Column(DateTime, nullable=True)
|
publishedAt = Column(DateTime, nullable=True)
|
||||||
deletedAt = Column(DateTime, nullable=True)
|
deletedAt = Column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init_table():
|
||||||
|
with local_session() as session:
|
||||||
|
entry = {
|
||||||
|
"slug": "genesis-block",
|
||||||
|
"body": "",
|
||||||
|
"title": "Ничего",
|
||||||
|
"lang": "ru"
|
||||||
|
}
|
||||||
|
s = Shout.create(**entry)
|
||||||
|
session.add(s)
|
||||||
|
session.commit()
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import JSON as JSONType
|
|
||||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, String
|
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, String
|
||||||
|
|
||||||
from base.orm import Base
|
from base.orm import Base
|
||||||
|
@ -25,10 +24,7 @@ class Topic(Base):
|
||||||
title = Column(String, nullable=False, comment="Title")
|
title = Column(String, nullable=False, comment="Title")
|
||||||
body = Column(String, nullable=True, comment="Body")
|
body = Column(String, nullable=True, comment="Body")
|
||||||
pic = Column(String, nullable=True, comment="Picture")
|
pic = Column(String, nullable=True, comment="Picture")
|
||||||
children = Column(
|
|
||||||
JSONType, nullable=True, default=[], comment="list of children topics"
|
|
||||||
)
|
|
||||||
community = Column(
|
community = Column(
|
||||||
ForeignKey("community.slug"), nullable=False, comment="Community"
|
ForeignKey("community.id"), default=1, comment="Community"
|
||||||
)
|
)
|
||||||
oid = Column(String, nullable=True, comment="Old ID")
|
oid = Column(String, nullable=True, comment="Old ID")
|
||||||
|
|
|
@ -25,6 +25,10 @@ class UserRating(Base):
|
||||||
user = Column(ForeignKey("user.slug"), primary_key=True)
|
user = Column(ForeignKey("user.slug"), primary_key=True)
|
||||||
value = Column(Integer)
|
value = Column(Integer)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init_table():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UserRole(Base):
|
class UserRole(Base):
|
||||||
__tablename__ = "user_role"
|
__tablename__ = "user_role"
|
||||||
|
@ -48,6 +52,7 @@ class AuthorFollower(Base):
|
||||||
|
|
||||||
class User(Base):
|
class User(Base):
|
||||||
__tablename__ = "user"
|
__tablename__ = "user"
|
||||||
|
default_user = None
|
||||||
|
|
||||||
email = Column(String, unique=True, nullable=False, comment="Email")
|
email = Column(String, unique=True, nullable=False, comment="Email")
|
||||||
username = Column(String, nullable=False, comment="Login")
|
username = Column(String, nullable=False, comment="Login")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import Column, DateTime, ForeignKey
|
from sqlalchemy import Column, DateTime, ForeignKey, Integer
|
||||||
from base.orm import Base
|
from base.orm import Base, local_session
|
||||||
|
|
||||||
|
|
||||||
class ViewedEntry(Base):
|
class ViewedEntry(Base):
|
||||||
|
@ -8,6 +8,18 @@ class ViewedEntry(Base):
|
||||||
|
|
||||||
viewer = Column(ForeignKey("user.slug"), default='anonymous')
|
viewer = Column(ForeignKey("user.slug"), default='anonymous')
|
||||||
shout = Column(ForeignKey("shout.slug"))
|
shout = Column(ForeignKey("shout.slug"))
|
||||||
|
amount = Column(Integer, default=1)
|
||||||
createdAt = Column(
|
createdAt = Column(
|
||||||
DateTime, nullable=False, default=datetime.now, comment="Created at"
|
DateTime, nullable=False, default=datetime.now, comment="Created at"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init_table():
|
||||||
|
with local_session() as session:
|
||||||
|
entry = {
|
||||||
|
"shout": "genesis-block",
|
||||||
|
"amount": 0
|
||||||
|
}
|
||||||
|
viewed = ViewedEntry.create(**entry)
|
||||||
|
session.add(viewed)
|
||||||
|
session.commit()
|
||||||
|
|
|
@ -33,7 +33,7 @@ async def get_author_stat(slug):
|
||||||
# TODO: implement author stat
|
# TODO: implement author stat
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
return {
|
return {
|
||||||
"shouts": session.query(ShoutAuthor).where(ShoutAuthor.author == slug).count(),
|
"shouts": session.query(ShoutAuthor).where(ShoutAuthor.user == slug).count(),
|
||||||
"followers": session.query(AuthorFollower).where(AuthorFollower.author == slug).count(),
|
"followers": session.query(AuthorFollower).where(AuthorFollower.author == slug).count(),
|
||||||
"followings": session.query(AuthorFollower).where(AuthorFollower.follower == slug).count(),
|
"followings": session.query(AuthorFollower).where(AuthorFollower.follower == slug).count(),
|
||||||
"rating": session.query(func.sum(UserRating.value)).where(UserRating.user == slug).first(),
|
"rating": session.query(func.sum(UserRating.value)).where(UserRating.user == slug).first(),
|
||||||
|
|
|
@ -37,6 +37,7 @@ type AuthorStat {
|
||||||
followers: Int
|
followers: Int
|
||||||
rating: Int
|
rating: Int
|
||||||
commented: Int
|
commented: Int
|
||||||
|
shouts: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -492,8 +493,6 @@ type Topic {
|
||||||
title: String
|
title: String
|
||||||
body: String
|
body: String
|
||||||
pic: String
|
pic: String
|
||||||
parents: [String] # NOTE: topic can have parent topics
|
|
||||||
children: [String] # and children
|
|
||||||
community: Community!
|
community: Community!
|
||||||
stat: TopicStat
|
stat: TopicStat
|
||||||
oid: String
|
oid: String
|
||||||
|
|
|
@ -2,9 +2,10 @@ import asyncio
|
||||||
|
|
||||||
from gql import Client, gql
|
from gql import Client, gql
|
||||||
from gql.transport.aiohttp import AIOHTTPTransport
|
from gql.transport.aiohttp import AIOHTTPTransport
|
||||||
|
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
|
from sqlalchemy import func, select
|
||||||
from orm.viewed import ViewedEntry
|
from orm.viewed import ViewedEntry
|
||||||
|
from orm.shout import ShoutTopic
|
||||||
from services.zine.topics import TopicStorage
|
from services.zine.topics import TopicStorage
|
||||||
from ssl import create_default_context
|
from ssl import create_default_context
|
||||||
|
|
||||||
|
@ -43,12 +44,13 @@ ssl = create_default_context()
|
||||||
class ViewedStorage:
|
class ViewedStorage:
|
||||||
lock = asyncio.Lock()
|
lock = asyncio.Lock()
|
||||||
by_topics = {}
|
by_topics = {}
|
||||||
|
by_shouts = {}
|
||||||
period = 5 * 60 # 5 minutes
|
period = 5 * 60 # 5 minutes
|
||||||
client = None
|
client = None
|
||||||
transport = None
|
transport = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def load_views(session):
|
async def update_views(session):
|
||||||
# TODO: when the struture of payload will be transparent
|
# TODO: when the struture of payload will be transparent
|
||||||
# TODO: perhaps ackee token getting here
|
# TODO: perhaps ackee token getting here
|
||||||
|
|
||||||
|
@ -61,18 +63,53 @@ class ViewedStorage:
|
||||||
print(domains)
|
print(domains)
|
||||||
print('\n\n# TODO: something here...\n\n')
|
print('\n\n# TODO: something here...\n\n')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get_shout(shout_slug):
|
||||||
|
self = ViewedStorage
|
||||||
|
async with self.lock:
|
||||||
|
r = self.by_shouts.get(shout_slug)
|
||||||
|
if r:
|
||||||
|
with local_session() as session:
|
||||||
|
shout_views = 0
|
||||||
|
shout_views_q = select(func.sum(ViewedEntry.amount)).where(
|
||||||
|
ViewedEntry.shout == shout_slug
|
||||||
|
)
|
||||||
|
shout_views = session.execute(shout_views_q)
|
||||||
|
self.by_shouts[shout_slug] = shout_views
|
||||||
|
return shout_views
|
||||||
|
else:
|
||||||
|
return r
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get_topic(topic_slug):
|
||||||
|
self = ViewedStorage
|
||||||
|
topic_views = 0
|
||||||
|
async with self.lock:
|
||||||
|
topic_views_by_shouts = self.by_topics.get(topic_slug) or {}
|
||||||
|
if len(topic_views_by_shouts.keys()) == 0:
|
||||||
|
with local_session() as session:
|
||||||
|
shoutslugs = session.query(ShoutTopic.shout).where(ShoutTopic.topic == topic_slug).all()
|
||||||
|
self.by_topics[topic_slug] = {}
|
||||||
|
for slug in shoutslugs:
|
||||||
|
self.by_topics[topic_slug][slug] = await self.get_shout(slug)
|
||||||
|
topic_views_by_shouts = self.by_topics.get(topic_slug) or {}
|
||||||
|
for shout in topic_views_by_shouts:
|
||||||
|
topic_views += shout
|
||||||
|
return topic_views
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def increment(shout_slug, amount=1, viewer='anonymous'):
|
async def increment(shout_slug, amount=1, viewer='anonymous'):
|
||||||
self = ViewedStorage
|
self = ViewedStorage
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
viewed = ViewedEntry.create({
|
viewed = ViewedEntry.create(**{
|
||||||
"viewer": viewer,
|
"viewer": viewer,
|
||||||
"shout": shout_slug
|
"shout": shout_slug,
|
||||||
|
"amount": amount
|
||||||
})
|
})
|
||||||
session.add(viewed)
|
session.add(viewed)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
self.by_shouts[shout_slug] = self.by_shouts.get(shout_slug, 0) + amount
|
||||||
shout_topics = await TopicStorage.get_topics_by_slugs([shout_slug, ])
|
shout_topics = await TopicStorage.get_topics_by_slugs([shout_slug, ])
|
||||||
for t in shout_topics:
|
for t in shout_topics:
|
||||||
self.by_topics[t] = self.by_topics.get(t) or {}
|
self.by_topics[t] = self.by_topics.get(t) or {}
|
||||||
|
@ -85,7 +122,7 @@ class ViewedStorage:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
await self.load_views(session)
|
await self.update_views(session)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
print("[stat.viewed] : %s" % (err))
|
print("[stat.viewed] : %s" % (err))
|
||||||
print("[stat.viewed] renew period: %d minutes" % (self.period / 60))
|
print("[stat.viewed] renew period: %d minutes" % (self.period / 60))
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
|
|
||||||
from gql import Client, gql
|
|
||||||
from gql.transport.aiohttp import AIOHTTPTransport
|
|
||||||
|
|
||||||
from base.redis import redis
|
|
||||||
from services.zine.topics import TopicStorage
|
|
||||||
from ssl import create_default_context
|
|
||||||
|
|
||||||
|
|
||||||
query_ackee_views = gql(
|
|
||||||
"""
|
|
||||||
query getDomainsFacts {
|
|
||||||
domains {
|
|
||||||
statistics {
|
|
||||||
views {
|
|
||||||
id
|
|
||||||
count
|
|
||||||
}
|
|
||||||
pages {
|
|
||||||
id
|
|
||||||
count
|
|
||||||
created
|
|
||||||
}
|
|
||||||
}
|
|
||||||
facts {
|
|
||||||
activeVisitors
|
|
||||||
# averageViews
|
|
||||||
# averageDuration
|
|
||||||
viewsToday
|
|
||||||
viewsMonth
|
|
||||||
viewsYear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
ssl = create_default_context()
|
|
||||||
|
|
||||||
|
|
||||||
class ViewStat:
|
|
||||||
lock = asyncio.Lock()
|
|
||||||
by_slugs = {}
|
|
||||||
by_topics = {}
|
|
||||||
period = 5 * 60 # 5 minutes
|
|
||||||
transport = AIOHTTPTransport(url="https://ackee.discours.io/", ssl=ssl)
|
|
||||||
client = Client(transport=transport, fetch_schema_from_transport=True)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def load_views():
|
|
||||||
# TODO: when the struture of paylod will be transparent
|
|
||||||
# TODO: perhaps ackee token getting here
|
|
||||||
|
|
||||||
self = ViewStat
|
|
||||||
async with self.lock:
|
|
||||||
self.by_topics = await redis.execute("GET", "views_by_topics")
|
|
||||||
if self.by_topics:
|
|
||||||
self.by_topics = dict(json.loads(self.by_topics))
|
|
||||||
else:
|
|
||||||
self.by_topics = {}
|
|
||||||
self.by_slugs = await redis.execute("GET", "views_by_shouts")
|
|
||||||
if self.by_slugs:
|
|
||||||
self.by_slugs = dict(json.loads(self.by_slugs))
|
|
||||||
else:
|
|
||||||
self.by_slugs = {}
|
|
||||||
domains = await self.client.execute_async(query_ackee_views)
|
|
||||||
print("[stat.ackee] loaded domains")
|
|
||||||
print(domains)
|
|
||||||
|
|
||||||
print('\n\n# TODO: something here...\n\n')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get_shout(shout_slug):
|
|
||||||
self = ViewStat
|
|
||||||
async with self.lock:
|
|
||||||
return self.by_slugs.get(shout_slug) or 0
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get_topic(topic_slug):
|
|
||||||
self = ViewStat
|
|
||||||
async with self.lock:
|
|
||||||
shouts = self.by_topics.get(topic_slug) or {}
|
|
||||||
topic_views = 0
|
|
||||||
for v in shouts.values():
|
|
||||||
topic_views += v
|
|
||||||
return topic_views
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def increment(shout_slug, amount=1):
|
|
||||||
self = ViewStat
|
|
||||||
async with self.lock:
|
|
||||||
self.by_slugs[shout_slug] = self.by_slugs.get(shout_slug) or 0
|
|
||||||
self.by_slugs[shout_slug] += amount
|
|
||||||
await redis.execute(
|
|
||||||
"SET",
|
|
||||||
f"views_by_shouts/{shout_slug}",
|
|
||||||
str(self.by_slugs[shout_slug])
|
|
||||||
)
|
|
||||||
shout_topics = await TopicStorage.get_topics_by_slugs([shout_slug, ])
|
|
||||||
for t in shout_topics:
|
|
||||||
self.by_topics[t] = self.by_topics.get(t) or {}
|
|
||||||
self.by_topics[t][shout_slug] = self.by_topics[t].get(shout_slug) or 0
|
|
||||||
self.by_topics[t][shout_slug] += amount
|
|
||||||
await redis.execute(
|
|
||||||
"SET",
|
|
||||||
f"views_by_topics/{t}/{shout_slug}",
|
|
||||||
str(self.by_topics[t][shout_slug])
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def reset():
|
|
||||||
self = ViewStat
|
|
||||||
self.by_topics = {}
|
|
||||||
self.by_slugs = {}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def worker():
|
|
||||||
self = ViewStat
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
await self.load_views()
|
|
||||||
except Exception as err:
|
|
||||||
print("[stat.ackee] : %s" % (err))
|
|
||||||
print("[stat.ackee] renew period: %d minutes" % (ViewStat.period / 60))
|
|
||||||
await asyncio.sleep(self.period)
|
|
Loading…
Reference in New Issue
Block a user