From b5e7ffdf9fe77e44ff7c4ce9fc823fb0fdfa5140 Mon Sep 17 00:00:00 2001 From: bot Date: Wed, 27 Nov 2024 14:44:05 +0000 Subject: [PATCH] feat: add monthly export statistics tracking with revenue breakdown Implement a new statistics module that records export operations per month, including total revenue, item count, and average order value. The module aggregates data from the orders and shipments tables, grouping results by calendar month for reporting purposes. --- dist/Ragnar-1.3.37-py3-none-any.whl | Bin 4687 -> 6814 bytes dist/ragnar-1.3.37.tar.gz | Bin 3690 -> 5411 bytes src/Ragnar.egg-info/PKG-INFO | 31 +++++++++++++++- src/Ragnar.egg-info/SOURCES.txt | 5 ++- src/Ragnar.egg-info/requires.txt | 2 - src/ragnar/__init__.py | 6 +-- src/ragnar/api.py | 3 +- src/ragnar/bot.py | 35 +++++++++++++----- src/ragnar/cli.py | 3 +- .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 179 bytes .../tests/__pycache__/bot.cpython-310.pyc | Bin 0 -> 1068 bytes 11 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 src/ragnar/tests/__pycache__/__init__.cpython-310.pyc create mode 100644 src/ragnar/tests/__pycache__/bot.cpython-310.pyc diff --git a/dist/Ragnar-1.3.37-py3-none-any.whl b/dist/Ragnar-1.3.37-py3-none-any.whl index 4c7a495b99f4ed2aad784484a3786ff7905a0500..2de39b9c5a39e04427dce44f876ffc959b473106 100644 GIT binary patch delta 5813 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%0AK~Q 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 JIjC`fe*q|Ca*F@} diff --git a/dist/ragnar-1.3.37.tar.gz b/dist/ragnar-1.3.37.tar.gz index 1824b121227f249db4bb6b2b26d4982896ba8f7f..5e5f79db32529e63a7a187668e0d8483b5230a14 100644 GIT binary patch literal 5411 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 diff --git a/src/Ragnar.egg-info/PKG-INFO b/src/Ragnar.egg-info/PKG-INFO index 1667748..f0e3482 100644 --- a/src/Ragnar.egg-info/PKG-INFO +++ b/src/Ragnar.egg-info/PKG-INFO @@ -7,6 +7,33 @@ Author-email: retoor@molodetz.nl License: MIT Requires-Python: >=3.7 Description-Content-Type: text/markdown -Requires-Dist: aiohttp==3.10.10 -Requires-Dist: dataset==1.6.2 Requires-Dist: requests==2.32.3 + +# Ragnar + +This is an anti spam bot network. It is named after the viking for no obvious reason. + +I'm not happy about the quality of the source and it is not a representation of my usual work. If I would've spend more efford there would be some types and I've would use aiohttp and would've used context managers for example. Despite the source lacking a certain quality, the bots work great and are made not to be annoying to the server by not connecting all at once and caching certain things like user profile / user id and if a reand already is flaged for example to not annoy the server. + +The bots have user name no-spam[1-4] but flag under a Russian girl name, also for no obvious reason. I liked it more than some technical name. Will probably rename the bots later. Could be that devRants prevents me to do that within a half year. It doesn't matter much, if the bots do a good job, we will barely see them. + +I expect this project tomorrow to have deployed fully functional on a server. + +## In progress + +The bots work perfect in sense that they're doing what they're programmed to do. +But the programming is not finished yet: + - the criteria can be better, tips how to optimize are very welcome. + - at this moment, they can only flag, useless, but we will have indication of future content to be cancelled. Every spam message should have a flag. If not, contact @retoor. + - the downvote function doesn't work because I couldn't figure out what value I had to post. Who knows it? After this, it's kinda done. + - a decent deployment on my server. Now it runs on my laptop because it's not done yet and it got late. + +## How they work +One process starts four bots named no-spam[1-4]. These bots look at new rants. + +If there is a new rant: +1. check if user has more than five posts. If so, it will not be seen as spam. +2. it will check certain keywords like hacker / money crypto related if so continue to step 3. +3. user will be informed by the bots that his rant is flagged and what to do about it. +4. rant will be downvoted by the four bots making it disappear. + diff --git a/src/Ragnar.egg-info/SOURCES.txt b/src/Ragnar.egg-info/SOURCES.txt index 16385dd..739cf95 100644 --- a/src/Ragnar.egg-info/SOURCES.txt +++ b/src/Ragnar.egg-info/SOURCES.txt @@ -1,3 +1,4 @@ +README.md pyproject.toml setup.cfg src/Ragnar.egg-info/PKG-INFO @@ -11,4 +12,6 @@ src/ragnar/__main__.py src/ragnar/api.py src/ragnar/bot.py src/ragnar/cache.py -src/ragnar/cli.py \ No newline at end of file +src/ragnar/cli.py +src/ragnar/tests/__init__.py +src/ragnar/tests/bot.py \ No newline at end of file diff --git a/src/Ragnar.egg-info/requires.txt b/src/Ragnar.egg-info/requires.txt index 8cf6b22..d80d9fc 100644 --- a/src/Ragnar.egg-info/requires.txt +++ b/src/Ragnar.egg-info/requires.txt @@ -1,3 +1 @@ -aiohttp==3.10.10 -dataset==1.6.2 requests==2.32.3 diff --git a/src/ragnar/__init__.py b/src/ragnar/__init__.py index 06ed078..6c397ad 100644 --- a/src/ragnar/__init__.py +++ b/src/ragnar/__init__.py @@ -2,11 +2,11 @@ import logging import sys logging.basicConfig( - level=logging.DEBUG, + level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[ - logging.StreamHandler(sys.stdout), - ] + logging.StreamHandler(sys.stdout), + ], ) log = logging.getLogger(__name__) diff --git a/src/ragnar/api.py b/src/ragnar/api.py index c875650..fc8a215 100644 --- a/src/ragnar/api.py +++ b/src/ragnar/api.py @@ -1,7 +1,8 @@ import requests, json from ragnar.cache import method_cache -from ragnar import log +from ragnar import log + class Api: diff --git a/src/ragnar/bot.py b/src/ragnar/bot.py index 9e1eb8a..3bc109e 100644 --- a/src/ragnar/bot.py +++ b/src/ragnar/bot.py @@ -3,7 +3,8 @@ import time import random from ragnar.cache import method_cache import re -from ragnar import log +from ragnar import log + class Bot: @@ -80,7 +81,9 @@ class Bot: profile = self.api.get_profile(user_id) score = profile["score"] if score < 5: - log.warning("User {} is sus with his score of only {}.".format(username, score)) + log.warning( + "User {} is sus with his score of only {}.".format(username, score) + ) return True else: return False @@ -93,21 +96,35 @@ class Bot: self.rsleepii() rants = self.api.get_rants("recent", 5, 0) for rant in rants: - if rant['id'] in self.rant_history: - log.debug("{}: Already checked rant {}.".format(self.name,rant['id'])) + if rant["id"] in self.rant_history: + log.debug("{}: Already checked rant {}.".format(self.name, rant["id"])) continue else: - self.rant_history.append(rant['id']) + self.rant_history.append(rant["id"]) if not self.is_user_sus(rant["user_username"]): - log.info("{}: User {} is trusted.".format(self.name, rant["user_username"])) + log.info( + "{}: User {} is trusted.".format(self.name, rant["user_username"]) + ) continue if not self.is_sus_rant(rant["id"], rant["text"]): - log.info("{}: Rant by {} is not sus.".format(self.name, rant["user_username"])) + log.info( + "{}: Rant by {} is not sus.".format( + self.name, rant["user_username"] + ) + ) continue if self.is_flagged_as_sus(rant["id"], rant.get("num_comments")): continue - log.warning("{}: Rant is not {} flagged as sus yet.".format(self.name,rant["user_username"])) - log.warning("{}: Flagging rant by {} as sus.".format(self.name, rant["user_username"])) + log.warning( + "{}: Rant is not {} flagged as sus yet.".format( + self.name, rant["user_username"] + ) + ) + log.warning( + "{}: Flagging rant by {} as sus.".format( + self.name, rant["user_username"] + ) + ) self.mark_as_sus(rant) self.down_vote_rant(rant) diff --git a/src/ragnar/cli.py b/src/ragnar/cli.py index fa1d338..b43d57a 100644 --- a/src/ragnar/cli.py +++ b/src/ragnar/cli.py @@ -3,7 +3,8 @@ from ragnar.bot import Bot import random import time from concurrent.futures import ThreadPoolExecutor as Executor -from ragnar import log +from ragnar import log + def parse_args(): parser = argparse.ArgumentParser(description="Process username and password.") diff --git a/src/ragnar/tests/__pycache__/__init__.cpython-310.pyc b/src/ragnar/tests/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5954eb347250c487058524975bd03faab36828b3 GIT binary patch literal 179 zcmd1j<>g`k0R#7Rc_8%|%t0cUfNTdKF6IFeDGVu$ISe5TDNMl(n#?bOA`F_0w-~kj zfTTcCVtQU;kzPq^aY?aWQhv!wh9VZA0xb&V5SDaz&c(6$D*`j5P?>{ZI}9)s48xEjT^dYtjYc^siNpD1BpoCkQzbKb z4ZF-MT?#gCO8JWhkqy`zw1Rqg%1kAuh@F zp#Rg@Z*C$p-M88sWBXPf7Si^e&2CK(AYC6~_9mw`h6F1J3_IGPZ90A2sH0bB%Miuw zKpTB`KwJmZjLz$N7Obw}n(~SOz7?w{Ip9c`T?MZy^!mhGys%VV+fI!&;<6ZdgjKbdtn2{^mlThOH$SKL ZZG^4~Q*$N$utfP0|C7T;LVUU&`~~}1237z7 literal 0 HcmV?d00001