stats refactored
This commit is contained in:
parent
dffdff2869
commit
4536370c79
|
@ -16,7 +16,7 @@ class RedisCache:
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
if self._instance is None:
|
if self._instance is None:
|
||||||
return
|
return
|
||||||
self._instance.close()
|
await self._instance.close()
|
||||||
# await self._instance.wait_closed() # deprecated
|
# await self._instance.wait_closed() # deprecated
|
||||||
self._instance = None
|
self._instance = None
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ async def shouts_handle(storage, args):
|
||||||
"""migrating content items one by one"""
|
"""migrating content items one by one"""
|
||||||
counter = 0
|
counter = 0
|
||||||
discours_author = 0
|
discours_author = 0
|
||||||
|
anonymous_author = 0
|
||||||
pub_counter = 0
|
pub_counter = 0
|
||||||
topics_dataset_bodies = []
|
topics_dataset_bodies = []
|
||||||
topics_dataset_tlist = []
|
topics_dataset_tlist = []
|
||||||
|
@ -104,6 +105,8 @@ async def shouts_handle(storage, args):
|
||||||
author: str = shout["authors"][0].dict()
|
author: str = shout["authors"][0].dict()
|
||||||
if author["slug"] == "discours":
|
if author["slug"] == "discours":
|
||||||
discours_author += 1
|
discours_author += 1
|
||||||
|
if author["slug"] == "anonymous":
|
||||||
|
anonymous_author += 1
|
||||||
# print('[migration] ' + shout['slug'] + ' with author ' + author)
|
# print('[migration] ' + shout['slug'] + ' with author ' + author)
|
||||||
|
|
||||||
if entry.get("published"):
|
if entry.get("published"):
|
||||||
|
@ -128,6 +131,7 @@ async def shouts_handle(storage, args):
|
||||||
print("[migration] " + str(counter) + " content items were migrated")
|
print("[migration] " + str(counter) + " content items were migrated")
|
||||||
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")
|
||||||
|
|
||||||
|
|
||||||
async def comments_handle(storage):
|
async def comments_handle(storage):
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__all__ = (["users", "tags", "content_items", "comments"],)
|
__all__ = (["users", "topics", "content_items", "comments"],)
|
||||||
|
|
|
@ -8,10 +8,11 @@ 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.community import Community
|
||||||
from orm.reaction import Reaction, ReactionKind
|
from orm.reaction import Reaction, ReactionKind
|
||||||
from orm.shout import Shout, ShoutTopic, User, ShoutReactionsFollower
|
from orm.shout import Shout, ShoutTopic, ShoutReactionsFollower
|
||||||
|
from orm.user import User
|
||||||
from orm.topic import TopicFollower
|
from orm.topic import TopicFollower
|
||||||
from services.stat.reacted import ReactedStorage
|
from services.stat.reacted import ReactedStorage
|
||||||
from services.stat.viewed import ViewedByDay
|
from services.stat.viewed import ViewedStorage
|
||||||
from services.zine.topics import TopicStorage
|
from services.zine.topics import TopicStorage
|
||||||
|
|
||||||
OLD_DATE = "2016-03-05 22:22:00.350000"
|
OLD_DATE = "2016-03-05 22:22:00.350000"
|
||||||
|
@ -137,8 +138,7 @@ async def migrate(entry, storage):
|
||||||
if userdata:
|
if userdata:
|
||||||
userslug = userdata.get('slug')
|
userslug = userdata.get('slug')
|
||||||
else:
|
else:
|
||||||
userslug = "discours" # bad old id slug is used here to change later
|
userslug = "anonymous" # bad old id slug was found
|
||||||
print('DISCOURS AUTHORED: ' + oid)
|
|
||||||
r["authors"] = [userslug, ]
|
r["authors"] = [userslug, ]
|
||||||
|
|
||||||
# slug
|
# slug
|
||||||
|
@ -336,7 +336,7 @@ async def migrate(entry, storage):
|
||||||
raise Exception("[migration] content_item.ratings error: \n%r" % content_rating)
|
raise Exception("[migration] content_item.ratings error: \n%r" % content_rating)
|
||||||
|
|
||||||
# shout views
|
# shout views
|
||||||
ViewedByDay.create(shout=shout_dict["slug"], value=entry.get("views", 1))
|
ViewedStorage.increment(shout_dict["slug"], amount=entry.get("views", 1))
|
||||||
# del shout_dict['ratings']
|
# del shout_dict['ratings']
|
||||||
shout_dict["oid"] = entry.get("_id")
|
shout_dict["oid"] = entry.get("_id")
|
||||||
storage["shouts"]["by_oid"][entry["_id"]] = shout_dict
|
storage["shouts"]["by_oid"][entry["_id"]] = shout_dict
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
{
|
{
|
||||||
|
"207": "207",
|
||||||
|
"90-e": "90s",
|
||||||
"1990-e": "90s",
|
"1990-e": "90s",
|
||||||
"2000-e": "2000s",
|
"2000-e": "2000s",
|
||||||
"90-e": "90s",
|
|
||||||
"207": "207",
|
|
||||||
"kartochki-rubinshteyna": "rubinstein-cards",
|
|
||||||
"Georgia": "georgia",
|
|
||||||
"Japan": "japan",
|
|
||||||
"Sweden": "sweden",
|
|
||||||
"abstraktsiya": "abstract",
|
"abstraktsiya": "abstract",
|
||||||
"absurdism": "absurdism",
|
"absurdism": "absurdism",
|
||||||
"acclimatization": "acclimatisation",
|
"acclimatization": "acclimatisation",
|
||||||
|
@ -14,8 +10,8 @@
|
||||||
"adolf-gitler": "adolf-hitler",
|
"adolf-gitler": "adolf-hitler",
|
||||||
"afrika": "africa",
|
"afrika": "africa",
|
||||||
"agata-kristi": "agatha-christie",
|
"agata-kristi": "agatha-christie",
|
||||||
"agressiya": "agression",
|
|
||||||
"agressivnoe-povedenie": "agression",
|
"agressivnoe-povedenie": "agression",
|
||||||
|
"agressiya": "agression",
|
||||||
"aktsii": "actions",
|
"aktsii": "actions",
|
||||||
"aktsionizm": "actionism",
|
"aktsionizm": "actionism",
|
||||||
"alber-kamyu": "albert-kamus",
|
"alber-kamyu": "albert-kamus",
|
||||||
|
@ -40,6 +36,7 @@
|
||||||
"andrey-tarkovskiy": "andrey-tarkovsky",
|
"andrey-tarkovskiy": "andrey-tarkovsky",
|
||||||
"angliyskie-istorii": "english-stories",
|
"angliyskie-istorii": "english-stories",
|
||||||
"angliyskiy-yazyk": "english-langugae",
|
"angliyskiy-yazyk": "english-langugae",
|
||||||
|
"ango": "ango",
|
||||||
"animation": "animation",
|
"animation": "animation",
|
||||||
"animatsiya": "animation",
|
"animatsiya": "animation",
|
||||||
"anime": "anime",
|
"anime": "anime",
|
||||||
|
@ -57,12 +54,13 @@
|
||||||
"aristotel": "aristotle",
|
"aristotel": "aristotle",
|
||||||
"arktika": "arctic",
|
"arktika": "arctic",
|
||||||
"armiya": "army",
|
"armiya": "army",
|
||||||
|
"armiya-1": "army",
|
||||||
"art": "art",
|
"art": "art",
|
||||||
"art-is": "art-is",
|
"art-is": "art-is",
|
||||||
"artists": "artists",
|
"artists": "artists",
|
||||||
"ateizm": "atheism",
|
"ateizm": "atheism",
|
||||||
"audiopoeziya": "audio-poetry",
|
|
||||||
"audio-poetry": "audio-poetry",
|
"audio-poetry": "audio-poetry",
|
||||||
|
"audiopoeziya": "audio-poetry",
|
||||||
"audiospektakl": "audio-spectacles",
|
"audiospektakl": "audio-spectacles",
|
||||||
"auktsyon": "auktsyon",
|
"auktsyon": "auktsyon",
|
||||||
"avangard": "avantgarde",
|
"avangard": "avantgarde",
|
||||||
|
@ -74,6 +72,7 @@
|
||||||
"bannye-chteniya": "sauna-reading",
|
"bannye-chteniya": "sauna-reading",
|
||||||
"bardsongs": "bardsongs",
|
"bardsongs": "bardsongs",
|
||||||
"bdsm": "bdsm",
|
"bdsm": "bdsm",
|
||||||
|
"beecake": "beecake",
|
||||||
"belarus": "belarus",
|
"belarus": "belarus",
|
||||||
"belgiya": "belgium",
|
"belgiya": "belgium",
|
||||||
"bertold-breht": "berttold-brecht",
|
"bertold-breht": "berttold-brecht",
|
||||||
|
@ -85,6 +84,7 @@
|
||||||
"biznes": "business",
|
"biznes": "business",
|
||||||
"blizhniy-vostok": "middle-east",
|
"blizhniy-vostok": "middle-east",
|
||||||
"blizost": "closeness",
|
"blizost": "closeness",
|
||||||
|
"blocked-in-russia": "blocked-in-russia",
|
||||||
"blokada": "blockade",
|
"blokada": "blockade",
|
||||||
"bob-dilan": "bob-dylan",
|
"bob-dilan": "bob-dylan",
|
||||||
"bog": "god",
|
"bog": "god",
|
||||||
|
@ -152,30 +152,40 @@
|
||||||
"demonstrations": "demonstrations",
|
"demonstrations": "demonstrations",
|
||||||
"depression": "depression",
|
"depression": "depression",
|
||||||
"derevnya": "village",
|
"derevnya": "village",
|
||||||
|
"derrida": "derrida",
|
||||||
"design": "design",
|
"design": "design",
|
||||||
"detskie-doma": "orphanages",
|
"detskie-doma": "orphanages",
|
||||||
"detstvo": "childhood",
|
"detstvo": "childhood",
|
||||||
|
"devyanostye": "90s",
|
||||||
|
"dialog": "dialogue",
|
||||||
"digital": "digital",
|
"digital": "digital",
|
||||||
"digital-art": "digital-art",
|
"digital-art": "digital-art",
|
||||||
|
"dinozavry": "dinosaurs",
|
||||||
"directing": "directing",
|
"directing": "directing",
|
||||||
"diskurs": "discours",
|
"diskurs": "discours",
|
||||||
"diskurs-1": "discourse",
|
"diskurs-1": "discourse",
|
||||||
|
"diskurs-analiz": "discourse-analytics",
|
||||||
"dissidenty": "dissidents",
|
"dissidenty": "dissidents",
|
||||||
"diy": "diy",
|
"diy": "diy",
|
||||||
"dmitriy-donskoy": "dmitriy-donskoy",
|
"dmitriy-donskoy": "dmitriy-donskoy",
|
||||||
"dmitriy-prigov": "dmitriy-prigov",
|
"dmitriy-prigov": "dmitriy-prigov",
|
||||||
|
"dnevnik-1": "dairy",
|
||||||
"dnevniki": "dairies",
|
"dnevniki": "dairies",
|
||||||
"documentary": "documentary",
|
"documentary": "documentary",
|
||||||
|
"dokumentalnaya-poeziya": "documentary-poetry",
|
||||||
"dokumenty": "doсuments",
|
"dokumenty": "doсuments",
|
||||||
"domashnee-nasilie": "home-terror",
|
"domashnee-nasilie": "home-terror",
|
||||||
"donald-tramp": "donald-trump",
|
"donald-tramp": "donald-trump",
|
||||||
"donbass": "donbass",
|
"donbass": "donbass",
|
||||||
|
"donbass-diary": "donbass-diary",
|
||||||
"donorstvo": "donation",
|
"donorstvo": "donation",
|
||||||
|
"dozhd": "rain",
|
||||||
"drama": "drama",
|
"drama": "drama",
|
||||||
"dramaturgy": "dramaturgy",
|
"dramaturgy": "dramaturgy",
|
||||||
"drawing": "drawing",
|
"drawing": "drawing",
|
||||||
"drevo-zhizni": "tree-of-life",
|
"drevo-zhizni": "tree-of-life",
|
||||||
"drugs": "drugs",
|
"drugs": "drugs",
|
||||||
|
"duh": "spirit",
|
||||||
"dzhaz": "jazz",
|
"dzhaz": "jazz",
|
||||||
"dzhek-keruak": "jack-keruak",
|
"dzhek-keruak": "jack-keruak",
|
||||||
"dzhim-morrison": "jim-morrison",
|
"dzhim-morrison": "jim-morrison",
|
||||||
|
@ -194,6 +204,7 @@
|
||||||
"ekspressionizm": "expressionism",
|
"ekspressionizm": "expressionism",
|
||||||
"ekstremizm": "extremism",
|
"ekstremizm": "extremism",
|
||||||
"ekzistentsializm-1": "existentialism",
|
"ekzistentsializm-1": "existentialism",
|
||||||
|
"ekzistentsiya": "existence",
|
||||||
"elections": "elections",
|
"elections": "elections",
|
||||||
"electronic": "electronics",
|
"electronic": "electronics",
|
||||||
"electronics": "electronics",
|
"electronics": "electronics",
|
||||||
|
@ -248,10 +259,12 @@
|
||||||
"futuristy": "futurists",
|
"futuristy": "futurists",
|
||||||
"futurizm": "futurism",
|
"futurizm": "futurism",
|
||||||
"galereya": "gallery",
|
"galereya": "gallery",
|
||||||
|
"galereya-anna-nova": "gallery-anna-nova",
|
||||||
"gdr": "gdr",
|
"gdr": "gdr",
|
||||||
"gender": "gender",
|
"gender": "gender",
|
||||||
"gendernyy-diskurs": "gender",
|
"gendernyy-diskurs": "gender",
|
||||||
"gennadiy-aygi": "gennadiy-aygi",
|
"gennadiy-aygi": "gennadiy-aygi",
|
||||||
|
"Georgia": "georgia",
|
||||||
"gerhard-rihter": "gerhard-rihter",
|
"gerhard-rihter": "gerhard-rihter",
|
||||||
"germaniya": "germany",
|
"germaniya": "germany",
|
||||||
"germenevtika": "hermeneutics",
|
"germenevtika": "hermeneutics",
|
||||||
|
@ -268,8 +281,11 @@
|
||||||
"gravyura": "engraving",
|
"gravyura": "engraving",
|
||||||
"grazhdanskaya-oborona": "grazhdanskaya-oborona",
|
"grazhdanskaya-oborona": "grazhdanskaya-oborona",
|
||||||
"gretsiya": "greece",
|
"gretsiya": "greece",
|
||||||
|
"griby": "mushrooms",
|
||||||
|
"gruziya-2": "georgia",
|
||||||
"gulag": "gulag",
|
"gulag": "gulag",
|
||||||
"han-batyy": "khan-batyy",
|
"han-batyy": "khan-batyy",
|
||||||
|
"hayku": "haiku",
|
||||||
"health": "health",
|
"health": "health",
|
||||||
"himiya": "chemistry",
|
"himiya": "chemistry",
|
||||||
"hip-hop": "hip-hop",
|
"hip-hop": "hip-hop",
|
||||||
|
@ -286,6 +302,7 @@
|
||||||
"idm": "idm",
|
"idm": "idm",
|
||||||
"igil": "isis",
|
"igil": "isis",
|
||||||
"igor-pomerantsev": "igor-pomerantsev",
|
"igor-pomerantsev": "igor-pomerantsev",
|
||||||
|
"igra": "game",
|
||||||
"igra-prestolov": "game-of-throne",
|
"igra-prestolov": "game-of-throne",
|
||||||
"igry": "games",
|
"igry": "games",
|
||||||
"iisus-hristos": "jesus-christ",
|
"iisus-hristos": "jesus-christ",
|
||||||
|
@ -312,6 +329,7 @@
|
||||||
"iskusstvennyy-intellekt": "artificial-intelligence",
|
"iskusstvennyy-intellekt": "artificial-intelligence",
|
||||||
"islam": "islam",
|
"islam": "islam",
|
||||||
"istoriya-moskvy": "moscow-history",
|
"istoriya-moskvy": "moscow-history",
|
||||||
|
"istoriya-nauki": "history-of-sceince",
|
||||||
"istoriya-teatra": "theatre-history",
|
"istoriya-teatra": "theatre-history",
|
||||||
"italiya": "italy",
|
"italiya": "italy",
|
||||||
"italyanskiy-yazyk": "italian-language",
|
"italyanskiy-yazyk": "italian-language",
|
||||||
|
@ -322,6 +340,7 @@
|
||||||
"ivan-krylov": "ivan-krylov",
|
"ivan-krylov": "ivan-krylov",
|
||||||
"izobreteniya": "inventions",
|
"izobreteniya": "inventions",
|
||||||
"izrail-1": "israel",
|
"izrail-1": "israel",
|
||||||
|
"Japan": "japan",
|
||||||
"jazz": "jazz",
|
"jazz": "jazz",
|
||||||
"john-lennon": "john-lennon",
|
"john-lennon": "john-lennon",
|
||||||
"journalism": "journalism",
|
"journalism": "journalism",
|
||||||
|
@ -329,12 +348,15 @@
|
||||||
"k-pop": "k-pop",
|
"k-pop": "k-pop",
|
||||||
"kalligrafiya": "calligraphy",
|
"kalligrafiya": "calligraphy",
|
||||||
"karikatura": "caricatures",
|
"karikatura": "caricatures",
|
||||||
|
"kartochki-rubinshteyna": "rubinstein-cards",
|
||||||
"katrin-nenasheva": "katrin-nenasheva",
|
"katrin-nenasheva": "katrin-nenasheva",
|
||||||
|
"kavarga": "kavarga",
|
||||||
"kavkaz": "caucasus",
|
"kavkaz": "caucasus",
|
||||||
"kazan": "kazan",
|
"kazan": "kazan",
|
||||||
"kiberbezopasnost": "cybersecurity",
|
"kiberbezopasnost": "cybersecurity",
|
||||||
"kinoklub": "cinema-club",
|
"kinoklub": "cinema-club",
|
||||||
"kirill-serebrennikov": "kirill-serebrennikov",
|
"kirill-serebrennikov": "kirill-serebrennikov",
|
||||||
|
"kladbische": "cemetery",
|
||||||
"klassika": "classic",
|
"klassika": "classic",
|
||||||
"kollektivnoe-bessoznatelnoe": "сollective-unconscious",
|
"kollektivnoe-bessoznatelnoe": "сollective-unconscious",
|
||||||
"komediya": "comedy",
|
"komediya": "comedy",
|
||||||
|
@ -342,12 +364,14 @@
|
||||||
"kommunizm": "communism",
|
"kommunizm": "communism",
|
||||||
"kommuny": "communes",
|
"kommuny": "communes",
|
||||||
"kompyuternye-igry": "computer-games",
|
"kompyuternye-igry": "computer-games",
|
||||||
|
"konets-vesny": "end-of-spring",
|
||||||
"konservatizm": "conservatism",
|
"konservatizm": "conservatism",
|
||||||
"kontrkultura": "counter-culture",
|
"kontrkultura": "counter-culture",
|
||||||
"kontseptualizm": "conceptualism",
|
"kontseptualizm": "conceptualism",
|
||||||
"korotkometrazhka": "cinema-shorts",
|
"korotkometrazhka": "cinema-shorts",
|
||||||
"kosmos": "cosmos",
|
"kosmos": "cosmos",
|
||||||
"kraudfanding": "crowdfunding",
|
"kraudfanding": "crowdfunding",
|
||||||
|
"kriptovalyuty": "cryptocurrencies",
|
||||||
"krizis": "crisis",
|
"krizis": "crisis",
|
||||||
"krov": "blood",
|
"krov": "blood",
|
||||||
"krym": "crimea",
|
"krym": "crimea",
|
||||||
|
@ -373,12 +397,15 @@
|
||||||
"lirika": "lirics",
|
"lirika": "lirics",
|
||||||
"literary-studies": "literary-studies",
|
"literary-studies": "literary-studies",
|
||||||
"literature": "literature",
|
"literature": "literature",
|
||||||
|
"literaturnyykaver": "literature-cover",
|
||||||
"lo-fi": "lo-fi",
|
"lo-fi": "lo-fi",
|
||||||
|
"lomonosov": "lomonosov",
|
||||||
"love": "love",
|
"love": "love",
|
||||||
"luzha-goluboy-krovi": "luzha-goluboy-krovi",
|
"luzha-goluboy-krovi": "luzha-goluboy-krovi",
|
||||||
"lyudvig-vitgenshteyn": "ludwig-wittgenstein",
|
"lyudvig-vitgenshteyn": "ludwig-wittgenstein",
|
||||||
"lzhedmitriy": "false-dmitry",
|
"lzhedmitriy": "false-dmitry",
|
||||||
"lzhenauka": "pseudoscience",
|
"lzhenauka": "pseudoscience",
|
||||||
|
"magiya": "magic",
|
||||||
"maks-veber": "max-weber",
|
"maks-veber": "max-weber",
|
||||||
"manifests": "manifests",
|
"manifests": "manifests",
|
||||||
"manipulyatsii-soznaniem": "mind-manipulation",
|
"manipulyatsii-soznaniem": "mind-manipulation",
|
||||||
|
@ -388,13 +415,12 @@
|
||||||
"marsel-dyushan": "marchel-duchamp",
|
"marsel-dyushan": "marchel-duchamp",
|
||||||
"martin-haydegger": "martin-hidegger",
|
"martin-haydegger": "martin-hidegger",
|
||||||
"matematika": "maths",
|
"matematika": "maths",
|
||||||
"vladimir-mayakovskiy": "vladimir-mayakovsky",
|
|
||||||
"mayakovskiy": "vladimir-mayakovsky",
|
"mayakovskiy": "vladimir-mayakovsky",
|
||||||
"ekzistentsiya": "existence",
|
|
||||||
"media": "media",
|
"media": "media",
|
||||||
"medicine": "medicine",
|
"medicine": "medicine",
|
||||||
"memuary": "memoirs",
|
"memuary": "memoirs",
|
||||||
"menedzhment": "management",
|
"menedzhment": "management",
|
||||||
|
"menty": "police",
|
||||||
"merab-mamardashvili": "merab-mamardashvili",
|
"merab-mamardashvili": "merab-mamardashvili",
|
||||||
"mest": "revenge",
|
"mest": "revenge",
|
||||||
"metamodernizm": "metamodern",
|
"metamodernizm": "metamodern",
|
||||||
|
@ -417,6 +443,7 @@
|
||||||
"moda": "fashion",
|
"moda": "fashion",
|
||||||
"modernizm": "modernism",
|
"modernizm": "modernism",
|
||||||
"mokyumentari": "mockumentary",
|
"mokyumentari": "mockumentary",
|
||||||
|
"molodezh": "youth",
|
||||||
"moloko-plus": "moloko-plus",
|
"moloko-plus": "moloko-plus",
|
||||||
"money": "money",
|
"money": "money",
|
||||||
"monologs": "monologues",
|
"monologs": "monologues",
|
||||||
|
@ -436,6 +463,7 @@
|
||||||
"muzhchiny": "man",
|
"muzhchiny": "man",
|
||||||
"myshlenie": "thinking",
|
"myshlenie": "thinking",
|
||||||
"nagornyy-karabah": "nagorno-karabakh",
|
"nagornyy-karabah": "nagorno-karabakh",
|
||||||
|
"nasilie-1": "violence",
|
||||||
"natsionalizm": "nationalism",
|
"natsionalizm": "nationalism",
|
||||||
"natsionalnaya-ideya": "national-idea",
|
"natsionalnaya-ideya": "national-idea",
|
||||||
"natsizm": "nazism",
|
"natsizm": "nazism",
|
||||||
|
@ -500,9 +528,12 @@
|
||||||
"poetry": "poetry",
|
"poetry": "poetry",
|
||||||
"poetry-of-squares": "poetry-of-squares",
|
"poetry-of-squares": "poetry-of-squares",
|
||||||
"poetry-slam": "poetry-slam",
|
"poetry-slam": "poetry-slam",
|
||||||
|
"pokoy": "peace",
|
||||||
"police": "police",
|
"police": "police",
|
||||||
"politics": "politics",
|
"politics": "politics",
|
||||||
|
"politzaklyuchennye": "political-prisoners",
|
||||||
"polsha": "poland",
|
"polsha": "poland",
|
||||||
|
"pomosch": "help",
|
||||||
"pop-art": "pop-art",
|
"pop-art": "pop-art",
|
||||||
"pop-culture": "pop-culture",
|
"pop-culture": "pop-culture",
|
||||||
"pornografiya": "pornography",
|
"pornografiya": "pornography",
|
||||||
|
@ -543,8 +574,10 @@
|
||||||
"pskov": "pskov",
|
"pskov": "pskov",
|
||||||
"psychiatry": "psychiatry",
|
"psychiatry": "psychiatry",
|
||||||
"psychology": "psychology",
|
"psychology": "psychology",
|
||||||
|
"ptitsy": "birds",
|
||||||
"punk": "punk",
|
"punk": "punk",
|
||||||
"r-b": "rnb",
|
"r-b": "rnb",
|
||||||
|
"rasizm": "racism",
|
||||||
"realizm": "realism",
|
"realizm": "realism",
|
||||||
"redaktura": "editorial",
|
"redaktura": "editorial",
|
||||||
"refleksiya": "reflection",
|
"refleksiya": "reflection",
|
||||||
|
@ -555,6 +588,7 @@
|
||||||
"renovatsiya": "renovation",
|
"renovatsiya": "renovation",
|
||||||
"rep": "rap",
|
"rep": "rap",
|
||||||
"reportage": "reportage",
|
"reportage": "reportage",
|
||||||
|
"reportazh-1": "reportage",
|
||||||
"repressions": "repressions",
|
"repressions": "repressions",
|
||||||
"research": "research",
|
"research": "research",
|
||||||
"retroveyv": "retrowave",
|
"retroveyv": "retrowave",
|
||||||
|
@ -570,13 +604,16 @@
|
||||||
"ronald-reygan": "ronald-reygan",
|
"ronald-reygan": "ronald-reygan",
|
||||||
"roskomnadzor": "roskomnadzor",
|
"roskomnadzor": "roskomnadzor",
|
||||||
"rossiyskoe-kino": "russian-cinema",
|
"rossiyskoe-kino": "russian-cinema",
|
||||||
|
"rouling": "rowling",
|
||||||
"rozhava": "rojava",
|
"rozhava": "rojava",
|
||||||
"rpts": "rpts",
|
"rpts": "rpts",
|
||||||
"rus-na-grani-sryva": "rus-na-grani-sryva",
|
"rus-na-grani-sryva": "rus-na-grani-sryva",
|
||||||
"russia": "russia",
|
"russia": "russia",
|
||||||
"russian-language": "russian-language",
|
"russian-language": "russian-language",
|
||||||
"russian-literature": "russian-literature",
|
"russian-literature": "russian-literature",
|
||||||
|
"russkaya-toska": "russian-toska",
|
||||||
"russkiy-mir": "russkiy-mir",
|
"russkiy-mir": "russkiy-mir",
|
||||||
|
"salo": "lard",
|
||||||
"salvador-dali": "salvador-dali",
|
"salvador-dali": "salvador-dali",
|
||||||
"samoidentifikatsiya": "self-identity",
|
"samoidentifikatsiya": "self-identity",
|
||||||
"samoopredelenie": "self-definition",
|
"samoopredelenie": "self-definition",
|
||||||
|
@ -591,6 +628,7 @@
|
||||||
"second-world-war": "second-world-war",
|
"second-world-war": "second-world-war",
|
||||||
"sekond-hend": "second-hand",
|
"sekond-hend": "second-hand",
|
||||||
"seksprosvet": "sex-education",
|
"seksprosvet": "sex-education",
|
||||||
|
"seksualnoe-nasilie": "sexual-violence",
|
||||||
"sekty": "sects",
|
"sekty": "sects",
|
||||||
"semiotics": "semiotics",
|
"semiotics": "semiotics",
|
||||||
"serbiya": "serbia",
|
"serbiya": "serbia",
|
||||||
|
@ -606,6 +644,7 @@
|
||||||
"siriya": "siria",
|
"siriya": "siria",
|
||||||
"skulptura": "sculpture",
|
"skulptura": "sculpture",
|
||||||
"slavoy-zhizhek": "slavoj-zizek",
|
"slavoy-zhizhek": "slavoj-zizek",
|
||||||
|
"smert-1": "death",
|
||||||
"smysl": "meaning",
|
"smysl": "meaning",
|
||||||
"sny": "dreams",
|
"sny": "dreams",
|
||||||
"sobytiya": "events",
|
"sobytiya": "events",
|
||||||
|
@ -637,10 +676,12 @@
|
||||||
"strah": "fear",
|
"strah": "fear",
|
||||||
"street-art": "street-art",
|
"street-art": "street-art",
|
||||||
"stsenarii": "scenarios",
|
"stsenarii": "scenarios",
|
||||||
|
"sud": "court",
|
||||||
"summary": "summary",
|
"summary": "summary",
|
||||||
"supergeroi": "superheroes",
|
"supergeroi": "superheroes",
|
||||||
"svetlana-aleksievich": "svetlana-aleksievich",
|
"svetlana-aleksievich": "svetlana-aleksievich",
|
||||||
"svobodu-ivanu-golunovu": "free-ivan-golunov",
|
"svobodu-ivanu-golunovu": "free-ivan-golunov",
|
||||||
|
"Sweden": "sweden",
|
||||||
"syurrealizm": "surrealism",
|
"syurrealizm": "surrealism",
|
||||||
"tales": "tales",
|
"tales": "tales",
|
||||||
"tanets": "dance",
|
"tanets": "dance",
|
||||||
|
@ -679,6 +720,7 @@
|
||||||
"tvorchestvo": "creativity",
|
"tvorchestvo": "creativity",
|
||||||
"ugnetennyy-zhilischnyy-klass": "oppressed-housing-class",
|
"ugnetennyy-zhilischnyy-klass": "oppressed-housing-class",
|
||||||
"uilyam-shekspir": "william-shakespeare",
|
"uilyam-shekspir": "william-shakespeare",
|
||||||
|
"ukraina-2": "ukraine",
|
||||||
"ukraine": "ukraine",
|
"ukraine": "ukraine",
|
||||||
"university": "university",
|
"university": "university",
|
||||||
"urban-studies": "urban-studies",
|
"urban-studies": "urban-studies",
|
||||||
|
@ -686,6 +728,7 @@
|
||||||
"usa": "usa",
|
"usa": "usa",
|
||||||
"ussr": "ussr",
|
"ussr": "ussr",
|
||||||
"utopiya": "utopia",
|
"utopiya": "utopia",
|
||||||
|
"utrata": "loss",
|
||||||
"valter-benyamin": "valter-benyamin",
|
"valter-benyamin": "valter-benyamin",
|
||||||
"varlam-shalamov": "varlam-shalamov",
|
"varlam-shalamov": "varlam-shalamov",
|
||||||
"vasiliy-ii-temnyy": "basil-ii-temnyy",
|
"vasiliy-ii-temnyy": "basil-ii-temnyy",
|
||||||
|
@ -714,6 +757,7 @@
|
||||||
"visual-culture": "visual-culture",
|
"visual-culture": "visual-culture",
|
||||||
"vizualnaya-poeziya": "visual-poetry",
|
"vizualnaya-poeziya": "visual-poetry",
|
||||||
"vladimir-lenin": "vladimir-lenin",
|
"vladimir-lenin": "vladimir-lenin",
|
||||||
|
"vladimir-mayakovskiy": "vladimir-mayakovsky",
|
||||||
"vladimir-nabokov": "vladimir-nabokov",
|
"vladimir-nabokov": "vladimir-nabokov",
|
||||||
"vladimir-putin": "vladimir-putin",
|
"vladimir-putin": "vladimir-putin",
|
||||||
"vladimir-sorokin": "vladimir-sorokin",
|
"vladimir-sorokin": "vladimir-sorokin",
|
||||||
|
@ -723,6 +767,7 @@
|
||||||
"vong-karvay": "wong-karwai",
|
"vong-karvay": "wong-karwai",
|
||||||
"vospominaniya": "memories",
|
"vospominaniya": "memories",
|
||||||
"vostok": "east",
|
"vostok": "east",
|
||||||
|
"voyna-na-ukraine": "war-in-ukraine",
|
||||||
"vremya": "time",
|
"vremya": "time",
|
||||||
"vudi-allen": "woody-allen",
|
"vudi-allen": "woody-allen",
|
||||||
"vynuzhdennye-otnosheniya": "forced-relationship",
|
"vynuzhdennye-otnosheniya": "forced-relationship",
|
||||||
|
@ -736,65 +781,21 @@
|
||||||
"yan-vermeer": "yan-vermeer",
|
"yan-vermeer": "yan-vermeer",
|
||||||
"yanka-dyagileva": "yanka-dyagileva",
|
"yanka-dyagileva": "yanka-dyagileva",
|
||||||
"yaponskaya-literatura": "japan-literature",
|
"yaponskaya-literatura": "japan-literature",
|
||||||
|
"yazychestvo": "paganism",
|
||||||
"youth": "youth",
|
"youth": "youth",
|
||||||
"yozef-rot": "yozef-rot",
|
"yozef-rot": "yozef-rot",
|
||||||
"yurgen-habermas": "jorgen-habermas",
|
"yurgen-habermas": "jorgen-habermas",
|
||||||
"za-liniey-mannergeyma": "behind-mannerheim-line",
|
"za-liniey-mannergeyma": "behind-mannerheim-line",
|
||||||
|
"zabota": "care",
|
||||||
"zahar-prilepin": "zahar-prilepin",
|
"zahar-prilepin": "zahar-prilepin",
|
||||||
"zakonodatelstvo": "laws",
|
"zakonodatelstvo": "laws",
|
||||||
"zakony-mira": "world-laws",
|
"zakony-mira": "world-laws",
|
||||||
"zametki": "notes",
|
"zametki": "notes",
|
||||||
"zhelanie": "wish",
|
"zhelanie": "wish",
|
||||||
"konets-vesny": "end-of-spring",
|
|
||||||
"zhivotnye": "animals",
|
"zhivotnye": "animals",
|
||||||
"zhoze-saramago": "jose-saramago",
|
"zhoze-saramago": "jose-saramago",
|
||||||
"zigmund-freyd": "sigmund-freud",
|
"zigmund-freyd": "sigmund-freud",
|
||||||
"zolotaya-orda": "golden-horde",
|
"zolotaya-orda": "golden-horde",
|
||||||
"zombi": "zombie",
|
"zombi": "zombie",
|
||||||
"zombi-simpsony": "zombie-simpsons",
|
"zombi-simpsony": "zombie-simpsons"
|
||||||
"rouling": "rowling",
|
|
||||||
"diskurs-analiz": "discourse-analytics",
|
|
||||||
"menty": "police",
|
|
||||||
"ptitsy": "birds",
|
|
||||||
"salo": "lard",
|
|
||||||
"rasizm": "racism",
|
|
||||||
"griby": "mushrooms",
|
|
||||||
"politzaklyuchennye": "political-prisoners",
|
|
||||||
"molodezh": "youth",
|
|
||||||
"blocked-in-russia": "blocked-in-russia",
|
|
||||||
"kavarga": "kavarga",
|
|
||||||
"galereya-anna-nova": "gallery-anna-nova",
|
|
||||||
"derrida": "derrida",
|
|
||||||
"dinozavry": "dinosaurs",
|
|
||||||
"beecake": "beecake",
|
|
||||||
"literaturnyykaver": "literature-cover",
|
|
||||||
"dialog": "dialogue",
|
|
||||||
"dozhd": "rain",
|
|
||||||
"pomosch": "help",
|
|
||||||
"igra": "game",
|
|
||||||
"reportazh-1": "reportage",
|
|
||||||
"armiya-1": "army",
|
|
||||||
"ukraina-2": "ukraine",
|
|
||||||
"nasilie-1": "violence",
|
|
||||||
"smert-1": "death",
|
|
||||||
"dnevnik-1": "dairy",
|
|
||||||
"voyna-na-ukraine": "war-in-ukraine",
|
|
||||||
"zabota": "care",
|
|
||||||
"ango": "ango",
|
|
||||||
"hayku": "haiku",
|
|
||||||
"utrata": "loss",
|
|
||||||
"pokoy": "peace",
|
|
||||||
"kladbische": "cemetery",
|
|
||||||
"lomonosov": "lomonosov",
|
|
||||||
"istoriya-nauki": "history-of-sceince",
|
|
||||||
"sud": "court",
|
|
||||||
"russkaya-toska": "russian-toska",
|
|
||||||
"duh": "spirit",
|
|
||||||
"devyanostye": "90s",
|
|
||||||
"seksualnoe-nasilie": "sexual-violence",
|
|
||||||
"gruziya-2": "georgia",
|
|
||||||
"dokumentalnaya-poeziya": "documentary-poetry",
|
|
||||||
"kriptovalyuty": "cryptocurrencies",
|
|
||||||
"magiya": "magic",
|
|
||||||
"yazychestvo": "paganism"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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 ViewedByDay
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"User",
|
"User",
|
||||||
|
@ -19,6 +20,7 @@ __all__ = [
|
||||||
"Notification",
|
"Notification",
|
||||||
"Reaction",
|
"Reaction",
|
||||||
"UserRating",
|
"UserRating",
|
||||||
|
"ViewedByDay"
|
||||||
]
|
]
|
||||||
|
|
||||||
Base.metadata.create_all(engine)
|
Base.metadata.create_all(engine)
|
||||||
|
@ -27,3 +29,5 @@ Resource.init_table()
|
||||||
User.init_table()
|
User.init_table()
|
||||||
Community.init_table()
|
Community.init_table()
|
||||||
Role.init_table()
|
Role.init_table()
|
||||||
|
|
||||||
|
# NOTE: keep orm module isolated
|
||||||
|
|
|
@ -2,10 +2,25 @@ from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import Column, String, ForeignKey, DateTime
|
from sqlalchemy import Column, String, ForeignKey, DateTime
|
||||||
from sqlalchemy import Enum
|
from sqlalchemy import Enum
|
||||||
|
from enum import Enum as Enumeration
|
||||||
|
|
||||||
from base.orm import Base
|
from base.orm import Base
|
||||||
from services.stat.reacted import ReactedStorage, ReactionKind
|
|
||||||
from services.stat.viewed import ViewedStorage
|
|
||||||
|
class ReactionKind(Enumeration):
|
||||||
|
AGREE = 1 # +1
|
||||||
|
DISAGREE = 2 # -1
|
||||||
|
PROOF = 3 # +1
|
||||||
|
DISPROOF = 4 # -1
|
||||||
|
ASK = 5 # +0 bookmark
|
||||||
|
PROPOSE = 6 # +0
|
||||||
|
QUOTE = 7 # +0 bookmark
|
||||||
|
COMMENT = 8 # +0
|
||||||
|
ACCEPT = 9 # +1
|
||||||
|
REJECT = 0 # -1
|
||||||
|
LIKE = 11 # +1
|
||||||
|
DISLIKE = 12 # -1
|
||||||
|
# TYPE = <reaction index> # rating diff
|
||||||
|
|
||||||
|
|
||||||
class Reaction(Base):
|
class Reaction(Base):
|
||||||
|
@ -26,12 +41,3 @@ class Reaction(Base):
|
||||||
range = Column(String, nullable=True, comment="Range in format <start index>:<end>")
|
range = Column(String, nullable=True, comment="Range in format <start index>:<end>")
|
||||||
kind = Column(Enum(ReactionKind), nullable=False, comment="Reaction kind")
|
kind = Column(Enum(ReactionKind), nullable=False, comment="Reaction kind")
|
||||||
oid = Column(String, nullable=True, comment="Old ID")
|
oid = Column(String, nullable=True, comment="Old ID")
|
||||||
|
|
||||||
@property
|
|
||||||
async def stat(self):
|
|
||||||
return {
|
|
||||||
"viewed": await ViewedStorage.get_reaction(self.id),
|
|
||||||
"reacted": len(await ReactedStorage.get_reaction(self.id)),
|
|
||||||
"rating": await ReactedStorage.get_reaction_rating(self.id),
|
|
||||||
"commented": len(await ReactedStorage.get_reaction_comments(self.id)),
|
|
||||||
}
|
|
||||||
|
|
22
orm/shout.py
22
orm/shout.py
|
@ -5,10 +5,16 @@ from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from base.orm import Base
|
from base.orm import Base
|
||||||
from orm.reaction import Reaction
|
from orm.reaction import Reaction
|
||||||
from orm.topic import Topic, ShoutTopic
|
from orm.topic import Topic
|
||||||
from orm.user import User
|
from orm.user import User
|
||||||
from services.stat.reacted import ReactedStorage
|
|
||||||
from services.stat.viewed import ViewedStorage
|
|
||||||
|
class ShoutTopic(Base):
|
||||||
|
__tablename__ = "shout_topic"
|
||||||
|
|
||||||
|
id = None # type: ignore
|
||||||
|
shout = Column(ForeignKey("shout.slug"), primary_key=True)
|
||||||
|
topic = Column(ForeignKey("topic.slug"), primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
class ShoutReactionsFollower(Base):
|
class ShoutReactionsFollower(Base):
|
||||||
|
@ -62,17 +68,9 @@ class Shout(Base):
|
||||||
createdAt = Column(DateTime, nullable=False, default=datetime.now, comment="Created at")
|
createdAt = Column(DateTime, nullable=False, default=datetime.now, comment="Created at")
|
||||||
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)
|
||||||
|
|
||||||
versionOf = Column(ForeignKey("shout.slug"), nullable=True)
|
versionOf = Column(ForeignKey("shout.slug"), nullable=True)
|
||||||
draft = Column(Boolean, default=False)
|
draft = Column(Boolean, default=False)
|
||||||
lang = Column(String, default='ru')
|
lang = Column(String, default='ru')
|
||||||
oid = Column(String, nullable=True)
|
oid = Column(String, nullable=True)
|
||||||
|
|
||||||
@property
|
|
||||||
async def stat(self):
|
|
||||||
return {
|
|
||||||
"viewed": await ViewedStorage.get_shout(self.slug),
|
|
||||||
"reacted": len(await ReactedStorage.get_shout(self.slug)),
|
|
||||||
"commented": len(await ReactedStorage.get_comments(self.slug)),
|
|
||||||
"rating": await ReactedStorage.get_rating(self.slug),
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,14 +5,6 @@ from sqlalchemy import Column, Boolean, String, ForeignKey, DateTime, JSON as JS
|
||||||
from base.orm import Base
|
from base.orm import Base
|
||||||
|
|
||||||
|
|
||||||
class ShoutTopic(Base):
|
|
||||||
__tablename__ = "shout_topic"
|
|
||||||
|
|
||||||
id = None # type: ignore
|
|
||||||
shout = Column(ForeignKey("shout.slug"), primary_key=True)
|
|
||||||
topic = Column(ForeignKey("topic.slug"), primary_key=True)
|
|
||||||
|
|
||||||
|
|
||||||
class TopicFollower(Base):
|
class TopicFollower(Base):
|
||||||
__tablename__ = "topic_followers"
|
__tablename__ = "topic_followers"
|
||||||
|
|
||||||
|
|
28
orm/user.py
28
orm/user.py
|
@ -82,17 +82,25 @@ class User(Base):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def init_table():
|
def init_table():
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
default = session.query(User).filter(User.slug == "discours").first()
|
default = session.query(User).filter(User.slug == "anonymous").first()
|
||||||
if not default:
|
if not default:
|
||||||
default = User.create(
|
defaul_dict = {
|
||||||
id=0,
|
"email": "noreply@discours.io",
|
||||||
email="welcome@discours.io",
|
"username": "noreply@discours.io",
|
||||||
username="welcome@discours.io",
|
"name": "Аноним",
|
||||||
name="Дискурс",
|
"slug": "anonymous",
|
||||||
slug="discours",
|
}
|
||||||
userpic="https://discours.io/images/logo-mini.svg",
|
default = User.create(**defaul_dict)
|
||||||
)
|
session.add(default)
|
||||||
|
discours_dict = {
|
||||||
|
"email": "welcome@discours.io",
|
||||||
|
"username": "welcome@discours.io",
|
||||||
|
"name": "Дискурс",
|
||||||
|
"slug": "discours",
|
||||||
|
}
|
||||||
|
discours = User.create(**discours_dict)
|
||||||
|
session.add(discours)
|
||||||
|
session.commit()
|
||||||
User.default_user = default
|
User.default_user = default
|
||||||
|
|
||||||
async def get_permission(self):
|
async def get_permission(self):
|
||||||
|
|
12
orm/viewed.py
Normal file
12
orm/viewed.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import Column, DateTime, ForeignKey, Integer
|
||||||
|
from base.orm import Base
|
||||||
|
|
||||||
|
|
||||||
|
class ViewedByDay(Base):
|
||||||
|
__tablename__ = "viewed_by_day"
|
||||||
|
|
||||||
|
id = None
|
||||||
|
shout = Column(ForeignKey("shout.slug"), primary_key=True)
|
||||||
|
day = Column(DateTime, primary_key=True, default=datetime.now)
|
||||||
|
value = Column(Integer)
|
|
@ -5,6 +5,7 @@ from resolvers.auth import (
|
||||||
register,
|
register,
|
||||||
confirm_email,
|
confirm_email,
|
||||||
auth_send_link,
|
auth_send_link,
|
||||||
|
get_current_user,
|
||||||
)
|
)
|
||||||
from resolvers.collab import remove_author, invite_author
|
from resolvers.collab import remove_author, invite_author
|
||||||
from resolvers.community import (
|
from resolvers.community import (
|
||||||
|
@ -18,7 +19,6 @@ from resolvers.community import (
|
||||||
from resolvers.editor import create_shout, delete_shout, update_shout
|
from resolvers.editor import create_shout, delete_shout, update_shout
|
||||||
from resolvers.profile import (
|
from resolvers.profile import (
|
||||||
get_users_by_slugs,
|
get_users_by_slugs,
|
||||||
get_current_user,
|
|
||||||
get_user_reacted_shouts,
|
get_user_reacted_shouts,
|
||||||
get_user_roles,
|
get_user_roles,
|
||||||
get_top_authors,
|
get_top_authors,
|
||||||
|
@ -44,7 +44,7 @@ from resolvers.zine import (
|
||||||
get_shout_by_slug,
|
get_shout_by_slug,
|
||||||
follow,
|
follow,
|
||||||
unfollow,
|
unfollow,
|
||||||
view_shout,
|
increment_view,
|
||||||
top_month,
|
top_month,
|
||||||
top_overall,
|
top_overall,
|
||||||
recent_published,
|
recent_published,
|
||||||
|
@ -65,8 +65,8 @@ __all__ = [
|
||||||
"confirm_email",
|
"confirm_email",
|
||||||
"auth_send_link",
|
"auth_send_link",
|
||||||
"sign_out",
|
"sign_out",
|
||||||
# profile
|
|
||||||
"get_current_user",
|
"get_current_user",
|
||||||
|
# profile
|
||||||
"get_users_by_slugs",
|
"get_users_by_slugs",
|
||||||
"get_user_roles",
|
"get_user_roles",
|
||||||
"get_top_authors",
|
"get_top_authors",
|
||||||
|
@ -80,7 +80,7 @@ __all__ = [
|
||||||
"top_month",
|
"top_month",
|
||||||
"top_overall",
|
"top_overall",
|
||||||
"top_viewed",
|
"top_viewed",
|
||||||
"view_shout",
|
"increment_view",
|
||||||
"get_shout_by_slug",
|
"get_shout_by_slug",
|
||||||
# editor
|
# editor
|
||||||
"create_shout",
|
"create_shout",
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from urllib.parse import quote_plus
|
from urllib.parse import quote_plus
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from auth.tokenstorage import TokenStorage
|
|
||||||
from graphql.type import GraphQLResolveInfo
|
from graphql.type import GraphQLResolveInfo
|
||||||
from transliterate import translit
|
from transliterate import translit
|
||||||
|
|
||||||
|
from auth.tokenstorage import TokenStorage
|
||||||
from auth.authenticate import login_required
|
from auth.authenticate import login_required
|
||||||
from auth.email import send_auth_email
|
from auth.email import send_auth_email
|
||||||
from auth.identity import Identity, Password
|
from auth.identity import Identity, Password
|
||||||
|
@ -20,6 +21,22 @@ from resolvers.profile import get_user_info
|
||||||
from settings import SESSION_TOKEN_HEADER
|
from settings import SESSION_TOKEN_HEADER
|
||||||
|
|
||||||
|
|
||||||
|
@mutation.field("refreshSession")
|
||||||
|
@login_required
|
||||||
|
async def get_current_user(_, info):
|
||||||
|
user = info.context["request"].user
|
||||||
|
user.lastSeen = datetime.now()
|
||||||
|
with local_session() as session:
|
||||||
|
session.add(user)
|
||||||
|
session.commit()
|
||||||
|
token = await TokenStorage.create_session(user)
|
||||||
|
return {
|
||||||
|
"token": token,
|
||||||
|
"user": user,
|
||||||
|
"info": await get_user_info(user.slug),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("confirmEmail")
|
@mutation.field("confirmEmail")
|
||||||
async def confirm_email(*_, confirm_token):
|
async def confirm_email(*_, confirm_token):
|
||||||
"""confirm owning email address"""
|
"""confirm owning email address"""
|
||||||
|
|
|
@ -99,3 +99,6 @@ async def get_my_collections(_, info):
|
||||||
session.query(Collection).when(Collection.createdBy == user_id).all()
|
session.query(Collection).when(Collection.createdBy == user_id).all()
|
||||||
)
|
)
|
||||||
return collections
|
return collections
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: get shouts list by collection
|
||||||
|
|
|
@ -13,7 +13,7 @@ from services.zine.shoutscache import prepare_shouts
|
||||||
|
|
||||||
@query.field("shoutsForFeed")
|
@query.field("shoutsForFeed")
|
||||||
@login_required
|
@login_required
|
||||||
def get_user_feed(_, info, offset, limit) -> List[Shout]:
|
async def get_user_feed(_, info, offset, limit) -> List[Shout]:
|
||||||
user = info.context["request"].user
|
user = info.context["request"].user
|
||||||
shouts = []
|
shouts = []
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
|
|
@ -1,23 +1,39 @@
|
||||||
from datetime import datetime
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from sqlalchemy import and_, desc
|
from sqlalchemy import and_, desc
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
from auth.authenticate import login_required
|
from auth.authenticate import login_required
|
||||||
from auth.tokenstorage import TokenStorage
|
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from base.resolvers import mutation, query
|
from base.resolvers import mutation, query
|
||||||
from orm.reaction import Reaction
|
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, UserRole, Role, UserRating, AuthorFollower
|
from orm.user import User, UserRole, Role, UserRating, AuthorFollower
|
||||||
from resolvers.community import get_followed_communities
|
from .community import get_followed_communities
|
||||||
from resolvers.inbox import get_unread_counter
|
from .inbox import get_unread_counter
|
||||||
from resolvers.reactions import get_shout_reactions
|
from .reactions import get_shout_reactions
|
||||||
|
from .topics import get_topic_stat
|
||||||
from services.auth.users import UserStorage
|
from services.auth.users import UserStorage
|
||||||
|
|
||||||
|
|
||||||
|
async def get_user_info(slug):
|
||||||
|
return {
|
||||||
|
"unread": await get_unread_counter(slug), # unread inbox messages counter
|
||||||
|
"topics": [t.slug for t in get_followed_topics(0, slug)], # followed topics slugs
|
||||||
|
"authors": [a.slug for a in get_followed_authors(0, slug)], # followed authors slugs
|
||||||
|
"reactions": [r.shout for r in get_shout_reactions(0, slug)], # followed reacted shouts slugs
|
||||||
|
"communities": [c.slug for c in get_followed_communities(0, slug)], # followed communities slugs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def get_author_stat(slug):
|
||||||
|
# TODO: implement author stat
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@query.field("userReactedShouts")
|
@query.field("userReactedShouts")
|
||||||
async def get_user_reacted_shouts(_, _info, slug, offset, limit) -> List[Shout]:
|
async def get_user_reacted_shouts(_, _info, slug, offset, limit) -> List[Shout]:
|
||||||
user = await UserStorage.get_user_by_slug(slug)
|
user = await UserStorage.get_user_by_slug(slug)
|
||||||
|
@ -38,20 +54,22 @@ async def get_user_reacted_shouts(_, _info, slug, offset, limit) -> List[Shout]:
|
||||||
|
|
||||||
@query.field("userFollowedTopics")
|
@query.field("userFollowedTopics")
|
||||||
@login_required
|
@login_required
|
||||||
def get_followed_topics(_, slug) -> List[Topic]:
|
async def get_followed_topics(_, slug) -> List[Topic]:
|
||||||
rows = []
|
topics = []
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
rows = (
|
topics = (
|
||||||
session.query(Topic)
|
session.query(Topic)
|
||||||
.join(TopicFollower)
|
.join(TopicFollower)
|
||||||
.where(TopicFollower.follower == slug)
|
.where(TopicFollower.follower == slug)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
return rows
|
for topic in topics:
|
||||||
|
topic.stat = await get_topic_stat(topic.slug)
|
||||||
|
return topics
|
||||||
|
|
||||||
|
|
||||||
@query.field("userFollowedAuthors")
|
@query.field("userFollowedAuthors")
|
||||||
def get_followed_authors(_, slug) -> List[User]:
|
async def get_followed_authors(_, slug) -> List[User]:
|
||||||
authors = []
|
authors = []
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
authors = (
|
authors = (
|
||||||
|
@ -60,6 +78,8 @@ def get_followed_authors(_, slug) -> List[User]:
|
||||||
.where(AuthorFollower.follower == slug)
|
.where(AuthorFollower.follower == slug)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
for author in authors:
|
||||||
|
author.stat = await get_author_stat(author.slug)
|
||||||
return authors
|
return authors
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,33 +95,6 @@ async def user_followers(_, slug) -> List[User]:
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
|
||||||
# for mutation.field("refreshSession")
|
|
||||||
async def get_user_info(slug):
|
|
||||||
return {
|
|
||||||
"unread": await get_unread_counter(slug),
|
|
||||||
"topics": [t.slug for t in get_followed_topics(0, slug)],
|
|
||||||
"authors": [a.slug for a in get_followed_authors(0, slug)],
|
|
||||||
"reactions": [r.shout for r in get_shout_reactions(0, slug)],
|
|
||||||
"communities": [c.slug for c in get_followed_communities(0, slug)],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("refreshSession")
|
|
||||||
@login_required
|
|
||||||
async def get_current_user(_, info):
|
|
||||||
user = info.context["request"].user
|
|
||||||
user.lastSeen = datetime.now()
|
|
||||||
with local_session() as session:
|
|
||||||
session.add(user)
|
|
||||||
session.commit()
|
|
||||||
token = await TokenStorage.create_session(user)
|
|
||||||
return {
|
|
||||||
"token": token,
|
|
||||||
"user": user,
|
|
||||||
"info": await get_user_info(user.slug),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@query.field("getUsersBySlugs")
|
@query.field("getUsersBySlugs")
|
||||||
async def get_users_by_slugs(_, _info, slugs):
|
async def get_users_by_slugs(_, _info, slugs):
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
|
|
@ -10,6 +10,16 @@ from orm.shout import ShoutReactionsFollower
|
||||||
from orm.user import User
|
from orm.user import User
|
||||||
from services.auth.users import UserStorage
|
from services.auth.users import UserStorage
|
||||||
from services.stat.reacted import ReactedStorage
|
from services.stat.reacted import ReactedStorage
|
||||||
|
from services.stat.viewed import ViewedStorage
|
||||||
|
|
||||||
|
|
||||||
|
async def get_reaction_stat(reaction_id):
|
||||||
|
return {
|
||||||
|
"viewed": await ViewedStorage.get_reaction(reaction_id),
|
||||||
|
"reacted": len(await ReactedStorage.get_reaction(reaction_id)),
|
||||||
|
"rating": await ReactedStorage.get_reaction_rating(reaction_id),
|
||||||
|
"commented": len(await ReactedStorage.get_reaction_comments(reaction_id)),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def reactions_follow(user, slug, auto=False):
|
def reactions_follow(user, slug, auto=False):
|
||||||
|
@ -61,6 +71,8 @@ async def create_reaction(_, info, inp):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[resolvers.reactions] error on reactions autofollowing: {e}")
|
print(f"[resolvers.reactions] error on reactions autofollowing: {e}")
|
||||||
|
|
||||||
|
reaction.stat = await get_reaction_stat(reaction.id)
|
||||||
|
|
||||||
return {"reaction": reaction}
|
return {"reaction": reaction}
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,6 +98,8 @@ async def update_reaction(_, info, inp):
|
||||||
reaction.range = inp.get("range")
|
reaction.range = inp.get("range")
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
reaction.stat = await get_reaction_stat(reaction.id)
|
||||||
|
|
||||||
return {"reaction": reaction}
|
return {"reaction": reaction}
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,6 +132,7 @@ async def get_shout_reactions(_, info, slug, offset, limit):
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
for r in reactions:
|
for r in reactions:
|
||||||
|
r.stat = await get_reaction_stat(r.id)
|
||||||
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
|
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
|
||||||
return reactions
|
return reactions
|
||||||
|
|
||||||
|
@ -137,6 +152,7 @@ async def get_reactions_for_shouts(_, info, shouts, offset, limit):
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
for r in reactions:
|
for r in reactions:
|
||||||
|
r.stat = await get_reaction_stat(r.id)
|
||||||
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
|
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
|
||||||
return reactions
|
return reactions
|
||||||
|
|
||||||
|
@ -152,5 +168,6 @@ async def get_reactions_by_author(_, info, slug, limit=50, offset=0):
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
)
|
)
|
||||||
for r in reactions:
|
for r in reactions:
|
||||||
|
r.stat = await get_reaction_stat(r.id)
|
||||||
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
|
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
|
||||||
return reactions
|
return reactions
|
||||||
|
|
|
@ -6,16 +6,30 @@ from auth.authenticate import login_required
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from base.resolvers import mutation, query
|
from base.resolvers import mutation, query
|
||||||
from orm.topic import Topic, TopicFollower
|
from orm.topic import Topic, TopicFollower
|
||||||
from services.stat.topicstat import TopicStat
|
|
||||||
from services.zine.shoutscache import ShoutsCache
|
from services.zine.shoutscache import ShoutsCache
|
||||||
from services.zine.topics import TopicStorage
|
from services.zine.topics import TopicStorage
|
||||||
|
from services.stat.reacted import ReactedStorage
|
||||||
|
from services.stat.topicstat import TopicStat
|
||||||
|
from services.stat.viewed import ViewedStorage
|
||||||
|
|
||||||
|
|
||||||
|
async def get_topic_stat(slug):
|
||||||
|
return {
|
||||||
|
"shouts": len(TopicStat.shouts_by_topic.get(slug, [])),
|
||||||
|
"authors": len(TopicStat.authors_by_topic.get(slug, [])),
|
||||||
|
"followers": len(TopicStat.followers_by_topic.get(slug, [])),
|
||||||
|
"viewed": await ViewedStorage.get_topic(slug),
|
||||||
|
"reacted": len(await ReactedStorage.get_topic(slug)),
|
||||||
|
"commented": len(await ReactedStorage.get_topic_comments(slug)),
|
||||||
|
"rating": await ReactedStorage.get_topic_rating(slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@query.field("topicsAll")
|
@query.field("topicsAll")
|
||||||
async def topics_all(_, _info):
|
async def topics_all(_, _info):
|
||||||
topics = await TopicStorage.get_topics_all()
|
topics = await TopicStorage.get_topics_all()
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
topic.stat = await TopicStat.get_stat(topic.slug)
|
topic.stat = await get_topic_stat(topic.slug)
|
||||||
return topics
|
return topics
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,17 +37,18 @@ async def topics_all(_, _info):
|
||||||
async def topics_by_community(_, info, community):
|
async def topics_by_community(_, info, community):
|
||||||
topics = await TopicStorage.get_topics_by_community(community)
|
topics = await TopicStorage.get_topics_by_community(community)
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
topic.stat = await TopicStat.get_stat(topic.slug)
|
topic.stat = await get_topic_stat(topic.slug)
|
||||||
return topics
|
return topics
|
||||||
|
|
||||||
|
|
||||||
@query.field("topicsByAuthor")
|
@query.field("topicsByAuthor")
|
||||||
async def topics_by_author(_, _info, author):
|
async def topics_by_author(_, _info, author):
|
||||||
topics = ShoutsCache.by_author.get(author)
|
shouts = ShoutsCache.by_author.get(author)
|
||||||
author_topics = set()
|
author_topics = set()
|
||||||
for tpc in topics:
|
for s in shouts:
|
||||||
|
for tpc in s.topics:
|
||||||
tpc = await TopicStorage.topics[tpc.slug]
|
tpc = await TopicStorage.topics[tpc.slug]
|
||||||
tpc.stat = await TopicStat.get_stat(tpc.slug)
|
tpc.stat = await get_topic_stat(tpc.slug)
|
||||||
author_topics.add(tpc)
|
author_topics.add(tpc)
|
||||||
return list(author_topics)
|
return list(author_topics)
|
||||||
|
|
||||||
|
@ -91,11 +106,8 @@ async def topics_random(_, info, amount=12):
|
||||||
topics = await TopicStorage.get_topics_all()
|
topics = await TopicStorage.get_topics_all()
|
||||||
normalized_topics = []
|
normalized_topics = []
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
topic_stat = await TopicStat.get_stat(topic.slug)
|
topic.stat = await get_topic_stat(topic.slug)
|
||||||
# FIXME: expects topicstat fix
|
if topic.stat["shouts"] > 2:
|
||||||
# #if topic_stat["shouts"] > 2:
|
|
||||||
# normalized_topics.append(topic)
|
|
||||||
topic.stat = topic_stat
|
|
||||||
normalized_topics.append(topic)
|
normalized_topics.append(topic)
|
||||||
sample_length = min(len(normalized_topics), amount)
|
sample_length = min(len(normalized_topics), amount)
|
||||||
return random.sample(normalized_topics, sample_length)
|
return random.sample(normalized_topics, sample_length)
|
||||||
|
|
|
@ -64,12 +64,6 @@ async def recent_reacted(_, _info, offset, limit):
|
||||||
return ShoutsCache.recent_reacted[offset : offset + limit]
|
return ShoutsCache.recent_reacted[offset : offset + limit]
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("viewShout")
|
|
||||||
async def view_shout(_, _info, slug):
|
|
||||||
await ViewedStorage.increment(slug)
|
|
||||||
return {"error": ""}
|
|
||||||
|
|
||||||
|
|
||||||
@query.field("getShoutBySlug")
|
@query.field("getShoutBySlug")
|
||||||
async def get_shout_by_slug(_, info, slug):
|
async def get_shout_by_slug(_, info, slug):
|
||||||
all_fields = [
|
all_fields = [
|
||||||
|
|
|
@ -157,8 +157,6 @@ type Mutation {
|
||||||
createShout(input: ShoutInput!): Result!
|
createShout(input: ShoutInput!): Result!
|
||||||
updateShout(input: ShoutInput!): Result!
|
updateShout(input: ShoutInput!): Result!
|
||||||
deleteShout(slug: String!): Result!
|
deleteShout(slug: String!): Result!
|
||||||
viewShout(slug: String!): Result!
|
|
||||||
viewReaction(reaction_id: Int!): Result!
|
|
||||||
|
|
||||||
# user profile
|
# user profile
|
||||||
rateUser(slug: String!, value: Int!): Result!
|
rateUser(slug: String!, value: Int!): Result!
|
||||||
|
|
|
@ -1,29 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime
|
from base.orm import local_session
|
||||||
from enum import Enum as Enumeration
|
from orm.reaction import ReactionKind, Reaction
|
||||||
|
from services.zine.topics import TopicStorage
|
||||||
from sqlalchemy import Column, DateTime, ForeignKey, Boolean
|
|
||||||
from sqlalchemy.orm.attributes import flag_modified
|
|
||||||
from sqlalchemy.types import Enum as ColumnEnum
|
|
||||||
|
|
||||||
from base.orm import Base, local_session
|
|
||||||
from orm.topic import ShoutTopic
|
|
||||||
|
|
||||||
|
|
||||||
class ReactionKind(Enumeration):
|
|
||||||
AGREE = 1 # +1
|
|
||||||
DISAGREE = 2 # -1
|
|
||||||
PROOF = 3 # +1
|
|
||||||
DISPROOF = 4 # -1
|
|
||||||
ASK = 5 # +0 bookmark
|
|
||||||
PROPOSE = 6 # +0
|
|
||||||
QUOTE = 7 # +0 bookmark
|
|
||||||
COMMENT = 8 # +0
|
|
||||||
ACCEPT = 9 # +1
|
|
||||||
REJECT = 0 # -1
|
|
||||||
LIKE = 11 # +1
|
|
||||||
DISLIKE = 12 # -1
|
|
||||||
# TYPE = <reaction index> # rating diff
|
|
||||||
|
|
||||||
|
|
||||||
def kind_to_rate(kind) -> int:
|
def kind_to_rate(kind) -> int:
|
||||||
|
@ -45,18 +23,6 @@ def kind_to_rate(kind) -> int:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
class ReactedByDay(Base):
|
|
||||||
__tablename__ = "reacted_by_day"
|
|
||||||
|
|
||||||
id = None # type: ignore
|
|
||||||
reaction = Column(ForeignKey("reaction.id"), primary_key=True)
|
|
||||||
shout = Column(ForeignKey("shout.slug"), primary_key=True)
|
|
||||||
replyTo = Column(ForeignKey("reaction.id"), nullable=True)
|
|
||||||
kind = Column(ColumnEnum(ReactionKind), nullable=False, comment="Reaction kind")
|
|
||||||
day = Column(DateTime, primary_key=True, default=datetime.now)
|
|
||||||
comment = Column(Boolean, default=False)
|
|
||||||
|
|
||||||
|
|
||||||
class ReactedStorage:
|
class ReactedStorage:
|
||||||
reacted = {"shouts": {}, "topics": {}, "reactions": {}}
|
reacted = {"shouts": {}, "topics": {}, "reactions": {}}
|
||||||
rating = {"shouts": {}, "topics": {}, "reactions": {}}
|
rating = {"shouts": {}, "topics": {}, "reactions": {}}
|
||||||
|
@ -64,6 +30,7 @@ class ReactedStorage:
|
||||||
to_flush = []
|
to_flush = []
|
||||||
period = 30 * 60 # sec
|
period = 30 * 60 # sec
|
||||||
lock = asyncio.Lock()
|
lock = asyncio.Lock()
|
||||||
|
modified_shouts = set([])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_shout(shout_slug):
|
async def get_shout(shout_slug):
|
||||||
|
@ -82,7 +49,7 @@ class ReactedStorage:
|
||||||
self = ReactedStorage
|
self = ReactedStorage
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
return list(
|
return list(
|
||||||
filter(lambda r: r.comment, self.reacted["shouts"].get(shout_slug, {}))
|
filter(lambda r: bool(r.body), self.reacted["shouts"].get(shout_slug, {}))
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -90,7 +57,7 @@ class ReactedStorage:
|
||||||
self = ReactedStorage
|
self = ReactedStorage
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
return list(
|
return list(
|
||||||
filter(lambda r: r.comment, self.reacted["topics"].get(topic_slug, []))
|
filter(lambda r: bool(r.body), self.reacted["topics"].get(topic_slug, []))
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -99,7 +66,7 @@ class ReactedStorage:
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
return list(
|
return list(
|
||||||
filter(
|
filter(
|
||||||
lambda r: r.comment, self.reacted["reactions"].get(reaction_id, {})
|
lambda r: bool(r.body), self.reacted["reactions"].get(reaction_id, {})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,118 +105,62 @@ class ReactedStorage:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def react(reaction):
|
async def react(reaction):
|
||||||
|
ReactedStorage.modified_shouts.add(reaction.shout)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def recount(reactions):
|
||||||
self = ReactedStorage
|
self = ReactedStorage
|
||||||
|
for r in reactions:
|
||||||
async with self.lock:
|
# renew shout counters
|
||||||
reactions = {}
|
self.reacted["shouts"][r.shout] = self.reacted["shouts"].get(r.shout, [])
|
||||||
|
self.reacted["shouts"][r.shout].append(r)
|
||||||
# iterate sibling reactions
|
# renew topics counters
|
||||||
reactions = self.reacted["shouts"].get(reaction.shout, {})
|
shout_topics = await TopicStorage.get_topics_by_slugs([r.shout, ])
|
||||||
for r in reactions.values():
|
for t in shout_topics:
|
||||||
reaction = ReactedByDay.create({
|
self.reacted["topics"][t] = self.reacted["topics"].get(t, [])
|
||||||
"day": datetime.now().replace(
|
self.reacted["topics"][t].append(r)
|
||||||
hour=0, minute=0, second=0, microsecond=0
|
self.rating["topics"][t] = \
|
||||||
),
|
self.rating["topics"].get(t, 0) + kind_to_rate(r.kind)
|
||||||
"reaction": r.id,
|
if r.replyTo:
|
||||||
"kind": r.kind,
|
# renew reaction counters
|
||||||
"shout": r.shout,
|
self.reacted["reactions"][r.replyTo] = \
|
||||||
"comment": bool(r.body),
|
self.reacted["reactions"].get(r.replyTo, [])
|
||||||
"replyTo": r.replyTo
|
self.reacted["reactions"][r.replyTo].append(r)
|
||||||
})
|
self.rating["reactions"][r.replyTo] = \
|
||||||
# renew sorted by shouts store
|
self.rating["reactions"].get(r.replyTo, 0) + kind_to_rate(r.kind)
|
||||||
self.reacted["shouts"][reaction.shout] = self.reacted["shouts"].get(reaction.shout, [])
|
|
||||||
self.reacted["shouts"][reaction.shout].append(reaction)
|
|
||||||
if reaction.replyTo:
|
|
||||||
self.reacted["reaction"][reaction.replyTo] = self.reacted[
|
|
||||||
"reactions"
|
|
||||||
].get(reaction.shout, [])
|
|
||||||
self.reacted["reaction"][reaction.replyTo].append(reaction)
|
|
||||||
self.rating["reactions"][reaction.replyTo] = self.rating[
|
|
||||||
"reactions"
|
|
||||||
].get(reaction.replyTo, 0) + kind_to_rate(reaction.kind)
|
|
||||||
else:
|
else:
|
||||||
# rate only by root reactions on shout
|
# renew shout rating
|
||||||
self.rating["shouts"][reaction.replyTo] = self.rating["shouts"].get(
|
self.rating["shouts"][r.shout] = \
|
||||||
reaction.shout, 0
|
self.rating["shouts"].get(r.shout, 0) + kind_to_rate(r.kind)
|
||||||
) + kind_to_rate(reaction.kind)
|
|
||||||
|
|
||||||
flag_modified(reaction, "value")
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def init(session):
|
def init(session):
|
||||||
self = ReactedStorage
|
self = ReactedStorage
|
||||||
all_reactions = session.query(ReactedByDay).all()
|
all_reactions = session.query(Reaction).all()
|
||||||
print("[stat.reacted] %d reactions total" % len(all_reactions))
|
self.modified_shouts = set([r.shout for r in all_reactions])
|
||||||
for reaction in all_reactions:
|
print("[stat.reacted] %d shouts with reactions updates" % len(self.modified_shouts))
|
||||||
shout = reaction.shout
|
|
||||||
topics = (
|
|
||||||
session.query(ShoutTopic.topic).where(ShoutTopic.shout == shout).all()
|
|
||||||
)
|
|
||||||
kind = reaction.kind
|
|
||||||
self.reacted["shouts"][shout] = self.reacted["shouts"].get(shout, [])
|
|
||||||
self.reacted["shouts"][shout].append(reaction)
|
|
||||||
self.rating["shouts"][shout] = self.rating["shouts"].get(
|
|
||||||
shout, 0
|
|
||||||
) + kind_to_rate(kind)
|
|
||||||
|
|
||||||
for t in topics:
|
|
||||||
self.reacted["topics"][t] = self.reacted["topics"].get(t, [])
|
|
||||||
self.reacted["topics"][t].append(reaction)
|
|
||||||
self.rating["topics"][t] = self.rating["topics"].get(
|
|
||||||
t, 0
|
|
||||||
) + kind_to_rate(
|
|
||||||
kind
|
|
||||||
) # rating
|
|
||||||
|
|
||||||
if reaction.replyTo:
|
|
||||||
self.reacted["reactions"][reaction.replyTo] = self.reacted[
|
|
||||||
"reactions"
|
|
||||||
].get(reaction.replyTo, [])
|
|
||||||
self.reacted["reactions"][reaction.replyTo].append(reaction)
|
|
||||||
self.rating["reactions"][reaction.replyTo] = self.rating[
|
|
||||||
"reactions"
|
|
||||||
].get(reaction.replyTo, 0) + kind_to_rate(reaction.kind)
|
|
||||||
ttt = self.reacted["topics"].values()
|
|
||||||
print("[stat.reacted] %d topics reacted" % len(ttt))
|
|
||||||
print("[stat.reacted] %d shouts reacted" % len(self.reacted["shouts"]))
|
|
||||||
print("[stat.reacted] %d reactions reacted" % len(self.reacted["reactions"]))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def flush_changes(session):
|
async def recount_changed(session):
|
||||||
self = ReactedStorage
|
self = ReactedStorage
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
for slug in dict(self.reacted["shouts"]).keys():
|
print('[stat.reacted] recounting...')
|
||||||
topics = (
|
for slug in list(self.modified_shouts):
|
||||||
session.query(ShoutTopic.topic)
|
siblings = session.query(Reaction).where(Reaction.shout == slug).all()
|
||||||
.where(ShoutTopic.shout == slug)
|
await self.recount(siblings)
|
||||||
.all()
|
|
||||||
)
|
print("[stat.reacted] %d shouts with reactions updates" % len(self.modified_shouts))
|
||||||
reactions = self.reacted["shouts"].get(slug, [])
|
print("[stat.reacted] %d topics reacted" % len(self.reacted["topics"].values()))
|
||||||
# print('[stat.reacted] shout {' + str(slug) + "}: " + str(len(reactions)))
|
print("[stat.reacted] %d shouts reacted" % len(self.reacted["shouts"]))
|
||||||
for ts in list(topics):
|
print("[stat.reacted] %d reactions reacted" % len(self.reacted["reactions"]))
|
||||||
tslug = ts[0]
|
self.modified_shouts = set([])
|
||||||
topic_reactions = self.reacted["topics"].get(tslug, [])
|
|
||||||
topic_reactions += reactions
|
|
||||||
# print('[stat.reacted] topic {' + str(tslug) + "}: " + str(len(topic_reactions)))
|
|
||||||
reactions += list(self.reacted["reactions"].values())
|
|
||||||
for reaction in reactions:
|
|
||||||
if getattr(reaction, "modified", False):
|
|
||||||
session.add(reaction)
|
|
||||||
flag_modified(reaction, "value")
|
|
||||||
reaction.modified = False
|
|
||||||
# print('flushing')
|
|
||||||
for reaction in self.to_flush:
|
|
||||||
session.add(reaction)
|
|
||||||
self.to_flush.clear()
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def worker():
|
async def worker():
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
await ReactedStorage().flush_changes(session)
|
await ReactedStorage.recount_changed(session)
|
||||||
print("[stat.reacted] periodical flush")
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
print("[stat.reacted] errror: %s" % (err))
|
print("[stat.reacted] recount error %s" % (err))
|
||||||
await asyncio.sleep(ReactedStorage.period)
|
await asyncio.sleep(ReactedStorage.period)
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from orm.shout import Shout
|
from orm.shout import Shout, ShoutTopic
|
||||||
from orm.topic import ShoutTopic, TopicFollower
|
from orm.topic import TopicFollower
|
||||||
from services.stat.reacted import ReactedStorage
|
|
||||||
from services.stat.viewed import ViewedStorage
|
|
||||||
from services.zine.shoutauthor import ShoutAuthorStorage
|
from services.zine.shoutauthor import ShoutAuthorStorage
|
||||||
|
|
||||||
|
|
||||||
class TopicStat:
|
class TopicStat:
|
||||||
shouts_by_topic = {}
|
shouts_by_topic = {} # Shout object stored
|
||||||
authors_by_topic = {}
|
authors_by_topic = {} # User
|
||||||
followers_by_topic = {}
|
followers_by_topic = {} # User
|
||||||
lock = asyncio.Lock()
|
lock = asyncio.Lock()
|
||||||
period = 30 * 60 # sec
|
period = 30 * 60 # sec
|
||||||
|
|
||||||
|
@ -19,37 +17,32 @@ class TopicStat:
|
||||||
async def load_stat(session):
|
async def load_stat(session):
|
||||||
self = TopicStat
|
self = TopicStat
|
||||||
shout_topics = session.query(ShoutTopic).all()
|
shout_topics = session.query(ShoutTopic).all()
|
||||||
print("[stat.topics] shout topics amount", len(shout_topics))
|
print("[stat.topics] shouts linked %d times" % len(shout_topics))
|
||||||
for shout_topic in shout_topics:
|
for shout_topic in shout_topics:
|
||||||
|
tpc = shout_topic.topic
|
||||||
# shouts by topics
|
# shouts by topics
|
||||||
topic = shout_topic.topic
|
shout = session.query(Shout).where(Shout.slug == shout_topic.shout).first()
|
||||||
shout = shout_topic.shout
|
self.shouts_by_topic[tpc] = self.shouts_by_topic.get(tpc, [])
|
||||||
sss = set(self.shouts_by_topic.get(topic, []))
|
if shout not in self.shouts_by_topic[tpc]:
|
||||||
shout = session.query(Shout).where(Shout.slug == shout).first()
|
self.shouts_by_topic[tpc].append(shout)
|
||||||
sss.union(
|
|
||||||
[
|
|
||||||
shout,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
self.shouts_by_topic[topic] = list(sss)
|
|
||||||
|
|
||||||
# authors by topics
|
# authors by topics
|
||||||
authors = await ShoutAuthorStorage.get_authors(shout)
|
authors = await ShoutAuthorStorage.get_authors(shout.slug)
|
||||||
aaa = set(self.authors_by_topic.get(topic, []))
|
self.authors_by_topic[tpc] = self.authors_by_topic.get(tpc, [])
|
||||||
aaa.union(authors)
|
for a in authors:
|
||||||
self.authors_by_topic[topic] = list(aaa)
|
if a not in self.authors_by_topic[tpc]:
|
||||||
|
self.authors_by_topic[tpc].append(a)
|
||||||
|
|
||||||
print("[stat.topics] authors sorted")
|
print("[stat.topics] shouts indexed by %d topics" % len(self.shouts_by_topic.keys()))
|
||||||
print("[stat.topics] shouts sorted")
|
print("[stat.topics] authors indexed by %d topics" % len(self.authors_by_topic.keys()))
|
||||||
|
|
||||||
self.followers_by_topic = {}
|
self.followers_by_topic = {}
|
||||||
followings = session.query(TopicFollower)
|
followings = session.query(TopicFollower).all()
|
||||||
for flw in followings:
|
for flw in followings:
|
||||||
topic = flw.topic
|
topic = flw.topic
|
||||||
user = flw.follower
|
user = flw.follower
|
||||||
if topic not in self.followers_by_topic:
|
self.followers_by_topic[topic] = self.followers_by_topic.get(topic, [])
|
||||||
self.followers_by_topic[topic] = []
|
if user not in self.followers_by_topic[topic]:
|
||||||
self.followers_by_topic[topic].append(user)
|
self.followers_by_topic[topic].append(user)
|
||||||
print("[stat.topics] followers sorted")
|
print("[stat.topics] followers sorted")
|
||||||
|
|
||||||
|
@ -59,23 +52,6 @@ class TopicStat:
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
return self.shouts_by_topic.get(topic, [])
|
return self.shouts_by_topic.get(topic, [])
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get_stat(topic):
|
|
||||||
self = TopicStat
|
|
||||||
async with self.lock:
|
|
||||||
shouts = self.shouts_by_topic.get(topic, [])
|
|
||||||
followers = self.followers_by_topic.get(topic, [])
|
|
||||||
authors = self.authors_by_topic.get(topic, [])
|
|
||||||
return {
|
|
||||||
"shouts": len(shouts),
|
|
||||||
"authors": len(authors),
|
|
||||||
"followers": len(followers),
|
|
||||||
"viewed": await ViewedStorage.get_topic(topic),
|
|
||||||
"reacted": len(await ReactedStorage.get_topic(topic)),
|
|
||||||
"commented": len(await ReactedStorage.get_topic_comments(topic)),
|
|
||||||
"rating": await ReactedStorage.get_topic_rating(topic),
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def worker():
|
async def worker():
|
||||||
self = TopicStat
|
self = TopicStat
|
||||||
|
@ -84,7 +60,6 @@ class TopicStat:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
await self.load_stat(session)
|
await self.load_stat(session)
|
||||||
print("[stat.topics] periodical update")
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
print("[stat.topics] errror: %s" % (err))
|
raise Exception(err)
|
||||||
await asyncio.sleep(self.period)
|
await asyncio.sleep(self.period)
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import Column, DateTime, ForeignKey, Integer
|
from base.orm import local_session
|
||||||
|
|
||||||
from sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
|
|
||||||
from base.orm import Base, local_session
|
from orm.shout import ShoutTopic
|
||||||
from orm.topic import ShoutTopic
|
from orm.viewed import ViewedByDay
|
||||||
|
|
||||||
|
|
||||||
class ViewedByDay(Base):
|
|
||||||
__tablename__ = "viewed_by_day"
|
|
||||||
|
|
||||||
id = None
|
|
||||||
shout = Column(ForeignKey("shout.slug"), primary_key=True)
|
|
||||||
day = Column(DateTime, primary_key=True, default=datetime.now)
|
|
||||||
value = Column(Integer)
|
|
||||||
|
|
||||||
|
|
||||||
class ViewedStorage:
|
class ViewedStorage:
|
||||||
|
@ -47,7 +39,7 @@ class ViewedStorage:
|
||||||
if this_day_view.day < view.day:
|
if this_day_view.day < view.day:
|
||||||
self.this_day_views[shout] = view
|
self.this_day_views[shout] = view
|
||||||
|
|
||||||
print("[stat.viewed] %d shouts viewed" % len(views))
|
print("[stat.viewed] %d shouts viewed" % len(self.viewed['shouts']))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_shout(shout_slug):
|
async def get_shout(shout_slug):
|
||||||
|
@ -68,7 +60,7 @@ class ViewedStorage:
|
||||||
return self.viewed["reactions"].get(reaction_id, 0)
|
return self.viewed["reactions"].get(reaction_id, 0)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def increment(shout_slug):
|
async def increment(shout_slug, amount=1):
|
||||||
self = ViewedStorage
|
self = ViewedStorage
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
this_day_view = self.this_day_views.get(shout_slug)
|
this_day_view = self.this_day_views.get(shout_slug)
|
||||||
|
@ -79,11 +71,9 @@ class ViewedStorage:
|
||||||
this_day_view = ViewedByDay.create(shout=shout_slug, value=1)
|
this_day_view = ViewedByDay.create(shout=shout_slug, value=1)
|
||||||
self.this_day_views[shout_slug] = this_day_view
|
self.this_day_views[shout_slug] = this_day_view
|
||||||
else:
|
else:
|
||||||
this_day_view.value = this_day_view.value + 1
|
this_day_view.value = this_day_view.value + amount
|
||||||
this_day_view.modified = True
|
this_day_view.modified = True
|
||||||
self.viewed["shouts"][shout_slug] = (
|
self.viewed["shouts"][shout_slug] = (self.viewed["shouts"].get(shout_slug, 0) + amount)
|
||||||
self.viewed["shouts"].get(shout_slug, 0) + 1
|
|
||||||
)
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
topics = (
|
topics = (
|
||||||
session.query(ShoutTopic.topic)
|
session.query(ShoutTopic.topic)
|
||||||
|
@ -91,7 +81,7 @@ class ViewedStorage:
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
for t in topics:
|
for t in topics:
|
||||||
self.viewed["topics"][t] = self.viewed["topics"].get(t, 0) + 1
|
self.viewed["topics"][t] = self.viewed["topics"].get(t, 0) + amount
|
||||||
flag_modified(this_day_view, "value")
|
flag_modified(this_day_view, "value")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -7,13 +7,23 @@ from sqlalchemy.orm import selectinload
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from orm.reaction import Reaction
|
from orm.reaction import Reaction
|
||||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
||||||
from services.stat.viewed import ViewedByDay
|
from services.stat.viewed import ViewedByDay, ViewedStorage
|
||||||
|
from services.stat.reacted import ReactedStorage
|
||||||
|
|
||||||
|
|
||||||
|
async def get_shout_stat(slug):
|
||||||
|
return {
|
||||||
|
"viewed": await ViewedStorage.get_shout(slug),
|
||||||
|
"reacted": len(await ReactedStorage.get_shout(slug)),
|
||||||
|
"commented": len(await ReactedStorage.get_comments(slug)),
|
||||||
|
"rating": await ReactedStorage.get_rating(slug),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def prepare_shouts(session, stmt):
|
async def prepare_shouts(session, stmt):
|
||||||
shouts = []
|
shouts = []
|
||||||
for s in list(map(lambda r: r.Shout, session.execute(stmt))):
|
for s in list(map(lambda r: r.Shout, session.execute(stmt))):
|
||||||
s.stats = await s.stat
|
s.stat = await get_shout_stat(s.slug)
|
||||||
shouts.append(s)
|
shouts.append(s)
|
||||||
return shouts
|
return shouts
|
||||||
|
|
||||||
|
@ -41,10 +51,14 @@ class ShoutsCache:
|
||||||
session,
|
session,
|
||||||
(
|
(
|
||||||
select(Shout)
|
select(Shout)
|
||||||
.options(selectinload(Shout.authors), selectinload(Shout.topics))
|
.options(
|
||||||
|
selectinload(Shout.authors),
|
||||||
|
selectinload(Shout.topics)
|
||||||
|
)
|
||||||
.where(bool(Shout.publishedAt))
|
.where(bool(Shout.publishedAt))
|
||||||
|
.filter(not bool(Shout.deletedAt))
|
||||||
.group_by(Shout.slug)
|
.group_by(Shout.slug)
|
||||||
.order_by(desc("publishedAt"))
|
.order_by(desc(Shout.publishedAt))
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -59,10 +73,13 @@ class ShoutsCache:
|
||||||
session,
|
session,
|
||||||
(
|
(
|
||||||
select(Shout)
|
select(Shout)
|
||||||
.options(selectinload(Shout.authors), selectinload(Shout.topics))
|
.options(
|
||||||
.where(and_(bool(Shout.publishedAt), bool(Reaction.deletedAt)))
|
selectinload(Shout.authors),
|
||||||
|
selectinload(Shout.topics)
|
||||||
|
)
|
||||||
|
.filter(not bool(Shout.deletedAt))
|
||||||
.group_by(Shout.slug)
|
.group_by(Shout.slug)
|
||||||
.order_by(desc("createdAt"))
|
.order_by(desc(Shout.createdAt))
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -73,22 +90,24 @@ class ShoutsCache:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def prepare_recent_reacted():
|
async def prepare_recent_reacted():
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
reactions = session.query(Reaction).order_by(Reaction.createdAt).limit(ShoutsCache.limit)
|
||||||
|
reacted_slugs = set([])
|
||||||
|
for r in reactions:
|
||||||
|
reacted_slugs.add(r.shout)
|
||||||
shouts = await prepare_shouts(
|
shouts = await prepare_shouts(
|
||||||
session,
|
session,
|
||||||
(
|
(
|
||||||
select(
|
select(Shout)
|
||||||
Shout, func.max(Reaction.createdAt).label("reactionCreatedAt")
|
|
||||||
)
|
|
||||||
.options(
|
.options(
|
||||||
selectinload(Shout.authors),
|
selectinload(Shout.authors),
|
||||||
selectinload(Shout.topics),
|
selectinload(Shout.topics),
|
||||||
)
|
)
|
||||||
.join(Reaction, Reaction.shout == Shout.slug)
|
.where(and_(bool(Shout.publishedAt), Shout.slug.in_(list(reacted_slugs))))
|
||||||
.where(and_(bool(Shout.publishedAt), bool(Reaction.deletedAt)))
|
.filter(not bool(Shout.deletedAt))
|
||||||
.group_by(Shout.slug)
|
.group_by(Shout.slug)
|
||||||
.order_by(desc("reactionCreatedAt"))
|
.order_by(Shout.publishedAt)
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
ShoutsCache.recent_reacted = shouts
|
ShoutsCache.recent_reacted = shouts
|
||||||
|
@ -114,7 +133,7 @@ class ShoutsCache:
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
shouts.sort(key=lambda s: s.stats["rating"], reverse=True)
|
shouts.sort(key=lambda s: s.stat["rating"], reverse=True)
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
print("[zine.cache] %d top shouts " % len(shouts))
|
print("[zine.cache] %d top shouts " % len(shouts))
|
||||||
ShoutsCache.top_overall = shouts
|
ShoutsCache.top_overall = shouts
|
||||||
|
@ -135,7 +154,7 @@ class ShoutsCache:
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
shouts.sort(key=lambda s: s.stats["rating"], reverse=True)
|
shouts.sort(key=lambda s: s.stat["rating"], reverse=True)
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
print("[zine.cache] %d top month shouts " % len(shouts))
|
print("[zine.cache] %d top month shouts " % len(shouts))
|
||||||
ShoutsCache.top_month = shouts
|
ShoutsCache.top_month = shouts
|
||||||
|
@ -156,7 +175,7 @@ class ShoutsCache:
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
shouts.sort(key=lambda s: s.stats["commented"], reverse=True)
|
shouts.sort(key=lambda s: s.stat["commented"], reverse=True)
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
print("[zine.cache] %d top commented shouts " % len(shouts))
|
print("[zine.cache] %d top commented shouts " % len(shouts))
|
||||||
ShoutsCache.top_viewed = shouts
|
ShoutsCache.top_viewed = shouts
|
||||||
|
@ -177,7 +196,7 @@ class ShoutsCache:
|
||||||
.limit(ShoutsCache.limit)
|
.limit(ShoutsCache.limit)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
shouts.sort(key=lambda s: s.stats["viewed"], reverse=True)
|
shouts.sort(key=lambda s: s.stat["viewed"], reverse=True)
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
print("[zine.cache] %d top viewed shouts " % len(shouts))
|
print("[zine.cache] %d top viewed shouts " % len(shouts))
|
||||||
ShoutsCache.top_viewed = shouts
|
ShoutsCache.top_viewed = shouts
|
||||||
|
@ -186,14 +205,10 @@ class ShoutsCache:
|
||||||
async def prepare_by_author():
|
async def prepare_by_author():
|
||||||
shouts_by_author = {}
|
shouts_by_author = {}
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
|
||||||
for a in session.query(ShoutAuthor).all():
|
for a in session.query(ShoutAuthor).all():
|
||||||
|
|
||||||
shout = session.query(Shout).filter(Shout.slug == a.shout).first()
|
shout = session.query(Shout).filter(Shout.slug == a.shout).first()
|
||||||
|
shout.stat = await get_shout_stat(shout.slug)
|
||||||
if not shouts_by_author.get(a.user):
|
shouts_by_author[a.user] = shouts_by_author.get(a.user, [])
|
||||||
shouts_by_author[a.user] = []
|
|
||||||
|
|
||||||
if shout not in shouts_by_author[a.user]:
|
if shout not in shouts_by_author[a.user]:
|
||||||
shouts_by_author[a.user].append(shout)
|
shouts_by_author[a.user].append(shout)
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
|
@ -204,17 +219,12 @@ class ShoutsCache:
|
||||||
async def prepare_by_topic():
|
async def prepare_by_topic():
|
||||||
shouts_by_topic = {}
|
shouts_by_topic = {}
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
for a in session.query(ShoutTopic).all():
|
||||||
for t in session.query(ShoutTopic).all():
|
shout = session.query(Shout).filter(Shout.slug == a.shout).first()
|
||||||
|
shout.stat = await get_shout_stat(shout.slug)
|
||||||
shout = session.query(Shout).filter(Shout.slug == t.shout).first()
|
shouts_by_topic[a.topic] = shouts_by_topic.get(a.topic, [])
|
||||||
|
if shout not in shouts_by_topic[a.topic]:
|
||||||
if not shouts_by_topic.get(t.topic):
|
shouts_by_topic[a.topic].append(shout)
|
||||||
shouts_by_topic[t.topic] = []
|
|
||||||
|
|
||||||
if shout not in shouts_by_topic[t.topic]:
|
|
||||||
shouts_by_topic[t.topic].append(shout)
|
|
||||||
|
|
||||||
async with ShoutsCache.lock:
|
async with ShoutsCache.lock:
|
||||||
print("[zine.cache] indexed by %d topics " % len(shouts_by_topic.keys()))
|
print("[zine.cache] indexed by %d topics " % len(shouts_by_topic.keys()))
|
||||||
ShoutsCache.by_topic = shouts_by_topic
|
ShoutsCache.by_topic = shouts_by_topic
|
||||||
|
|
Loading…
Reference in New Issue
Block a user