Esempio n. 1
0
def main():
    logging.info("Starting main")
    with open(os.path.join('..', 'cfg-tlgrm.json'), 'r',
              encoding='utf-8') as config_file:
        config_data = json.load(config_file)
        TOKEN = config_data['TOKEN']
        SUBREDDIT = config_data['SUBREDDIT']
        CHANNEL = config_data['CHANNEL']
        DBFILE = config_data['DBFILE']

    logging.info("Setting up Reddit connection")
    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         user_agent=config.USER_AGENT)
    reddit.read_only = True
    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()
    subreddit = reddit.subreddit(SUBREDDIT)

    killhandler = KillHandler()

    logging.info("Setting up database")
    conn = sqlite3.connect(DBFILE)
    conn.execute('CREATE TABLE IF NOT EXISTS posts (id)')
    conn.commit()

    logging.info("Setting up Telegram connection")
    tbot = telegram.Bot(token=TOKEN)
    try:
        tbot.get_me()
    except telegram.error.TelegramError as e_teleg:
        logging.error(e_teleg)
        logging.critical("Telegram error!")
        exit()

    for submission in subreddit.stream.submissions(pause_after=6):
        if submission:
            c = conn.cursor()
            c.execute('SELECT * FROM posts WHERE id=?', (submission.id, ))
            if not c.fetchone():
                link = 'https://redd.it/{id}'.format(id=submission.id)
                title = html.escape(submission.title or '')
                message_template = '<a href=\'{}\'>{}</a>'.format(link, title)
                logging.info('Posting %s', link)
                tbot.sendMessage(chat_id=CHANNEL,
                                 parse_mode=telegram.ParseMode.HTML,
                                 text=message_template)
                conn.execute('INSERT INTO posts (id) values (?)',
                             (submission.id, ))
                conn.commit()
            c.close()
        if killhandler.killed:
            logging.info("Termination signal received - exiting")
            break
    conn.close()
Esempio n. 2
0
def main():
    logging.info("Starting leaderboard...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    while not killhandler.killed:
        sess = session_maker()

        top_users = sess.query(
                Investor.name,
                func.coalesce(Investor.balance+func.sum(Investment.amount), Investor.balance).label('networth')).\
                outerjoin(Investment, and_(Investor.name == Investment.name, Investment.done == 0)).\
            group_by(Investor.name).\
            order_by(desc('networth')).\
            limit(10).\
            all()

        top_firms = sess.query(Firm).\
            filter(Firm.size > 0).\
            order_by(Firm.balance.desc()).\
            limit(10).\
            all()

        top_users_text = "Rank|User|Net Worth\n"
        top_users_text += ":-:|:-:|:-:\n"
        for i, user in enumerate(top_users):
            top_users_text += f"{i + 1}|/u/{user.name}|{formatNumber(user.networth)} MC\n"

        top_firms_text = "Rank|Firm|Total Assets|Level|Tax Rate\n"
        top_firms_text += ":-:|:-:|:-:|:-:|:-:\n"
        for i, firm in enumerate(top_firms):
            is_private = '(**P**) ' if firm.private else ''
            top_firms_text += f"{i + 1}|{is_private}{firm.name}|{formatNumber(firm.balance)} MC|{firm.rank + 1}|{firm.tax}%\n"

        sidebar_text = sidebar_text_org.\
            replace("%TOP_USERS%", top_users_text).\
            replace("%TOP_FIRMS%", top_firms_text)

        logging.info(" -- Updating sidebar text to:")
        logging.info(sidebar_text)
        for subreddit in config.SUBREDDITS:
            reddit.subreddit(subreddit).mod.update(description=sidebar_text)

        sess.commit()

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits['remaining'])
        res = int(reddit.auth.limits['reset_timestamp'] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem,
                     res)

        sess.close()

        time.sleep(config.LEADERBOARD_INTERVAL)
Esempio n. 3
0
def main():
    logging.info("Starting leaderboard...")

    engine = create_engine()
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    # We will test our reddit connection here
    if not config.TEST and not test_reddit_connection(reddit):
        exit()

    sess = session_maker()

    # query
    top_users = (sess.query(
        Investor.name,
        func.coalesce(Investor.balance + func.sum(Investment.amount),
                      Investor.balance).label("networth"),
    ).outerjoin(Investment,
                and_(Investor.name == Investment.name,
                     Investment.done == 0)).group_by(Investor.name).order_by(
                         desc("networth")).limit(500).all())
    top_poster = sess.execute(
        """
    SELECT  name,
            SUM(oc) AS coc,
            SUM(CASE OC WHEN 1 THEN final_upvotes ELSE 0 END) AS soc,
            count(*) as ct,
            sum(final_upvotes) as st
    FROM "Buyables"
    WHERE done = 1
    GROUP BY name
    ORDER BY coc DESC, soc DESC
    LIMIT :limit""",
        {
            "limit": 100
        },
    ).fetchall()

    # Sidebar
    sidebar_text = f"""
/r/BancaDelMeme è un posto dove si puoi comprare, vendere,
condividere, fare e investire sui meme liberamente.

*****

**Migliori utenti:**

{format_investor(top_users, 10)}

[Classifica completa](/r/BancaDelMeme/wiki/leaderboardbig)


**Migliori autori di OC:**

{format_posters_small(top_poster, 3)}

[Classifica completa](/r/BancaDelMeme/wiki/leaderboardocbig)

Ultimo aggiornamento: {localtime}


###***[Inviaci dei suggerimenti!](https://www.reddit.com/message/compose?to=%2Fr%2FBancaDelMeme)***

&nbsp;

***

**Subreddit ai quali potresti essere interessato:**

/r/italy

***
***
"""

    # redesign
    if not config.TEST:
        for subreddit in config.SUBREDDITS:
            # poster
            for widget in reddit.subreddit(subreddit).widgets.sidebar:
                if isinstance(widget, praw.models.TextArea):
                    if widget.shortName.lower().replace(" ", "") == "top10":
                        widget.mod.update(text=format_investor(top_users, 10))
                        logging.info(" -- Updated redesign top10: %s",
                                     subreddit)
                        break
            # investor
            for widget in reddit.subreddit(subreddit).widgets.sidebar:
                if isinstance(widget, praw.models.TextArea):
                    if widget.shortName.lower() == "migliori autori":
                        widget.mod.update(
                            text=format_posters_small(top_poster, 4))
                        logging.info(
                            " -- Updated redesign migliori autori: %s",
                            subreddit)
                        break

    # Old and wiki
    logging.info(" -- Updating sidebar text to:")
    logging.info(sidebar_text.replace("\n", "\\n"))
    if not config.TEST:
        for subreddit in config.SUBREDDITS:
            sub = reddit.subreddit(subreddit)
            # Sidebar update
            sub.mod.update(description=sidebar_text)
            logging.info("Updated sidebar: %s", subreddit)
            # wiki full poster
            wikipage = sub.wiki["leaderboardocbig"]
            wikipage.edit(format_posters_full(top_poster, 100))
            logging.info("Updated wiki poster: %s", subreddit)
            # wiki full investor
            wikipage = sub.wiki["leaderboardbig"]
            wikipage.edit(format_investor(top_users, 500))
            logging.info("Updated wiki investor: %s", subreddit)

    # Report the Reddit API call stats
    rem = int(reddit.auth.limits["remaining"])
    res = int(reddit.auth.limits["reset_timestamp"] - time.time())
    logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem, res)

    sess.close()
Esempio n. 4
0
def main():
    """
    This is the main function that listens to new submissions
    and then posts the ATTENTION sticky comment.
    """
    logging.info("Starting submitter...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    sess_maker = scoped_session(sessionmaker(bind=engine))

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    logging.info("Starting checking submissions...")

    stopwatch = Stopwatch()

    sess = sess_maker()
    submission_time = int(time.time())

    minimum_fee = config.SUBMISSION_MIN_FEE

    for submission in reddit.subreddit('+'.join(config.SUBREDDITS)).\
        stream.submissions(skip_existing=True):

        duration = stopwatch.measure()

        logging.info("New submission: %s", submission)
        logging.info(" -- retrieved in %ss", duration)

        # We don't need to post a sticky on stickied posts
        if submission.stickied:
            logging.info(" -- skipping (stickied)")
            continue

        # We are looking if the post is created in the past
        # so we won't double charge it
        if submission.created_utc < submission_time:
            logging.info(" -- skipping (timeout)")
            continue

        submission_time = int(submission.created_utc)
        logging.info(" -- Submission timestamp: %s", \
                     time.asctime(time.gmtime(submission_time)))

        bot_reply = 0
        delete_post = False

        # This is a bit of a controversial update, so im gonna make it
        # agile to switch between different modes
        if not config.SUBMISSION_FEE:
            # Post a comment to let people know where to invest
            bot_reply = submission.reply_wrap(
                message.invest_no_fee(f"u/{submission.author.name}"))
        else:
            # If a poster doesn't have an account, delete the post
            # if he has, take 1000 MemeCoins and invest them
            investor = sess.query(Investor).\
                filter(Investor.name == submission.author.name).\
                first()

            if not investor:
                bot_reply = submission.reply_wrap(message.NO_ACCOUNT_POST_ORG)
                delete_post = True
                logging.info(" -- Not a registered investor!")
            elif investor.balance < minimum_fee:
                bot_reply = submission.reply_wrap(
                    message.modify_pay_to_post(investor.balance))
                delete_post = True
                logging.info(" -- Not enough funds!")
            else:
                # We will make it 6%
                required_fee = int(investor.balance *
                                   (config.SUBMISSION_FEE_PERCENT / 100))
                if required_fee < minimum_fee:
                    required_fee = minimum_fee
                new_balance = investor.balance - required_fee
                investor.balance = new_balance
                bot_reply = submission.\
                    reply_wrap(message.modify_invest_place_here(required_fee,
                                                                f"u/{submission.author.name}"))
                sess.commit()

        # Sticky the comment
        if config.IS_MODERATOR:
            bot_reply.mod.distinguish(how='yes', sticky=True)
            bot_reply.mod.approve()
            if delete_post:
                logging.info(" -- Deleting the post...")
                #Should we hide or just delete the post?
                submission.mod.remove()

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        if killhandler.killed:
            logging.info("Termination signal received - exiting")
            break
Esempio n. 5
0
def main():
    logging.info("Starting calculator...")

    killhandler = KillHandler()

    engine = create_engine()
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        return ()

    praw.models.Comment.edit_wrap = edit_wrap
    stopwatch = Stopwatch()

    logging.info("Retrieving top ...")

    # query
    sess = session_maker()
    try:
        top_networth = (sess.query(
            Investor.name,
            func.coalesce(Investor.balance + func.sum(Investment.amount),
                          Investor.balance).label("networth"),
        ).outerjoin(
            Investment,
            and_(Investor.name == Investment.name,
                 Investment.done == 0)).group_by(Investor.name).order_by(
                     desc("networth")).limit(1).one())[1]
    except NoResultFound:
        top_networth = 0
    top_networth = max(top_networth,
                       config.STARTING_BALANCE * 10)  # al last starting * 10
    sess.close()
    logging.info("Top networth: %d", top_networth)

    logging.info("Monitoring active investments...")

    while not killhandler.killed:
        sess = session_maker()

        then = int(time.time()) - config.INVESTMENT_DURATION
        investment = (sess.query(Investment).filter(
            Investment.done == 0).filter(Investment.time < then).order_by(
                Investment.time.asc()).first())

        if not investment:
            # Nothing matured yet; wait a bit before trying again
            time.sleep(50)
            continue

        duration = stopwatch.measure()

        investor = sess.query(Investor).filter(
            Investor.name == investment.name).one()
        net_worth = investor.networth(sess)

        logging.info("New mature investment: %s", investment.comment)
        logging.info(" -- by %s", investor.name)

        # Retrieve the post the user invested in (lazily, no API call)
        post = reddit.submission(investment.post)

        # Retrieve the post's current upvote count (triggers an API call)
        upvotes_now = post.ups
        investment.final_upvotes = upvotes_now
        investment.op = (post.author and investor.name == post.author.name)
        investment.net_worth = net_worth
        investment.top_networth = top_networth

        # Updating the investor's balance
        factor = formula.calculate(upvotes_now, investment.upvotes, net_worth,
                                   top_networth)

        if factor > 1 and post.author and investor.name == post.author.name:
            # bonus per OP
            factor *= formula.OP_BONUS

        amount = investment.amount
        balance = investor.balance

        new_balance = int(balance + (amount * factor))
        change = new_balance - balance
        profit = change - amount

        # Updating the investor's variables
        investor.completed += 1

        # Retrieve the bot's original response (lazily, no API call)
        if investment.response != "0":
            response = reddit.comment(id=investment.response)
        else:
            response = EmptyResponse()

        if new_balance < BALANCE_CAP:
            # If investor is in a firm and he profits,
            # 15% goes to the firm
            investor.balance = new_balance

            # Edit the bot's response (triggers an API call)
            if profit > 0:
                logging.info(" -- profited %s", profit)
            elif profit == 0:
                logging.info(" -- broke even")
            else:
                logging.info(" -- lost %s", profit)

            edited_response = message.modify_invest_return(
                investment.amount,
                investment.upvotes,
                upvotes_now,
                change,
                profit,
                investor.balance,
            )

            response.edit_wrap(edited_response)
        else:
            # This investment pushed the investor's balance over the cap
            investor.balance = BALANCE_CAP

            # Edit the bot's response (triggers an API call)
            logging.info(" -- profited %s but got capped", profit)
            response.edit_wrap(
                message.modify_invest_capped(
                    investment.amount,
                    investment.upvotes,
                    upvotes_now,
                    change,
                    profit,
                    investor.balance,
                ))

        investment.success = profit > 0
        investment.profit = profit
        investment.done = True

        sess.commit()

        if top_networth < investor.balance:
            top_networth = investor.balance
            logging.info("New Top networth: %d", top_networth)

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits["remaining"])
        res = int(reddit.auth.limits["reset_timestamp"] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem,
                     res)

        sess.close()
Esempio n. 6
0
def main():
    logging.info("Starting buyable...")

    engine = create_engine()
    session_maker = sessionmaker(bind=engine, autoflush=False)

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    # We will test our reddit connection here
    if not test_reddit_connection(reddit):
        exit()

    praw.models.Comment.edit_wrap = edit_wrap

    stopwatch = Stopwatch()

    logging.info("Fetching active buyable...")

    sess = session_maker()

    then = int(time.time()) - config.INVESTMENT_DURATION
    buyables = (
        sess.query(Buyable)
        .filter(Buyable.done == 0)
        .filter(Buyable.time < then)
        .order_by(Buyable.time.asc())
    )

    for buyable in buyables:
        duration = stopwatch.measure()

        logging.info("New mature investment: %s", buyable.post)
        logging.info(" -- by %s", buyable.name)
        # Retrieve the post
        submission = reddit.submission(id=buyable.post)
        buyable.final_upvotes = submission.ups
        if submission.removed or not submission.author:
            logging.info(" -- deleted or removed")
            # buyable.done = True
            sess.delete(buyable)
            sess.commit()
            duration = stopwatch.measure()
            logging.info(" -- processed in %.2fs", duration)
            continue
        # valid OC only if not deleted/removed
        if submission.stickied or submission.distinguished:
            logging.info(" -- stickied or distinguished")
            # buyable.done = True
            sess.delete(buyable)
            sess.commit()
            duration = stopwatch.measure()
            logging.info(" -- processed in %.2fs", duration)
            continue
        buyable.oc = submission.link_flair_text == "OC"
        if not buyable.oc:
            logging.info(" -- not OC")
            buyable.done = True
            sess.commit()
            duration = stopwatch.measure()
            logging.info(" -- processed in %.2fs", duration)
            continue

        # Retrieve OP
        investor = sess.query(Investor).filter(Investor.name == buyable.name).first()
        if not investor:
            logging.info(" -- OP not investor")
            buyable.done = True
            sess.commit()
            duration = stopwatch.measure()
            logging.info(" -- processed in %.2fs", duration)
            continue
        balance = investor.balance

        # Retrieve the post investments
        investments = (
            sess.query(Investment)
            .filter(Investment.post == buyable.post)
            .filter(Investment.name != buyable.name)
        )
        profit = 0
        for investment in investments:
            profit += investment.amount / OC_BONUS
        net_worth = investor.networth(sess)
        if net_worth > 0:
            profit = int(min(profit, net_worth))

        # Updating the investor's balance
        new_balance = int(balance + profit)

        # Retrieve the bot's original response (lazily, no API call)
        if buyable.response != "0":
            response = reddit.comment(id=buyable.response)
        else:
            response = EmptyResponse()

        if new_balance < BALANCE_CAP:
            investor.balance = new_balance

            # Edit the bot's response (triggers an API call)
            logging.info(" -- profited %d", profit)

            response.edit_wrap(response.body + message.modify_oc_return(profit))
        else:
            # This investment pushed the investor's balance over the cap
            investor.balance = BALANCE_CAP

            # Edit the bot's response (triggers an API call)
            logging.info(" -- profited %d but got capped", profit)
            response.edit_wrap(response.body + message.modify_oc_capped())

        buyable.profit = profit
        buyable.done = True

        sess.commit()

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits["remaining"])
        res = int(reddit.auth.limits["reset_timestamp"] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem, res)

    sess.close()
Esempio n. 7
0
def main():
    logging.info("Starting leaderboard...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not config.TEST and not utils.test_reddit_connection(reddit):
        exit()

    sess = session_maker()

    top_users = sess.query(
            Investor.name,
            func.coalesce(Investor.balance+func.sum(Investment.amount), Investor.balance).label('networth')).\
            outerjoin(Investment, and_(Investor.name == Investment.name, Investment.done == 0)).\
        group_by(Investor.name).\
        order_by(desc('networth')).\
        limit(10).\
        all()

    top_users_text = ".|Utente|Patrimonio\n"
    top_users_text += ":-:|:-:|:-:\n"
    for i, user in enumerate(top_users):
        top_users_text += f"{i + 1}|/u/{user.name}|{formatNumber(user.networth)} M€\n"

    top_users_text += """

[Classifica completa](/r/BancaDelMeme/wiki/leaderboardbig)"""

    sidebar_text = sidebar_text_org.\
        replace("%TOP_USERS%", top_users_text).\
        replace("%LOCALTIME%", localtime)

    # redesign
    if not config.TEST:
        for subreddit in config.SUBREDDITS:
            for widget in reddit.subreddit(subreddit).widgets.sidebar:
                if isinstance(widget, praw.models.TextArea):
                    if widget.shortName.lower().replace(" ", "") == 'top10':
                        widget.mod.update(text=top_users_text)
                        break

    top_poster = sess.execute(
        """
    SELECT  name,
            SUM(oc) AS coc,
            SUM(CASE OC WHEN 1 THEN final_upvotes ELSE 0 END) AS soc
    FROM "Buyables"
    WHERE done = 1 AND time > :since
    GROUP BY name
    ORDER BY coc DESC, soc DESC
    LIMIT :limit""", {
            "since": 1579020536,
            "limit": 5
        })

    top_poster_text = "Autore|#OC|Karma|\n"
    top_poster_text += ":-:|:-:|:-:|:-:|:-:\n"
    for poster in top_poster:
        top_poster_text += f"/u/{poster[0]}|{poster[1]}|{poster[2]}\n"
    top_poster_text += """

[Classifica completa](/r/BancaDelMeme/wiki/leaderboardocbig)"""
    sidebar_text = sidebar_text.\
        replace("%TOP_OC%", top_poster_text)
    if not config.TEST:
        # redesign
        for subreddit in config.SUBREDDITS:
            for widget in reddit.subreddit(subreddit).widgets.sidebar:
                if isinstance(widget, praw.models.TextArea):
                    if widget.shortName.lower() == 'migliori autori':
                        widget.mod.update(text=top_poster_text)
                        break

    # Sidebar update
    logging.info(" -- Updating sidebar text to:")
    logging.info(sidebar_text)
    if not config.TEST:
        for subreddit in config.SUBREDDITS:
            reddit.subreddit(subreddit).mod.update(description=sidebar_text)

    sess.commit()

    # Report the Reddit API call stats
    rem = int(reddit.auth.limits['remaining'])
    res = int(reddit.auth.limits['reset_timestamp'] - time.time())
    logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem, res)

    sess.close()
Esempio n. 8
0
def main():
    logging.info("Starting calculator...")
    logging.info(
        "Sleeping for 8 seconds. Waiting for the database to turn on...")
    time.sleep(8)

    killhandler = KillHandler()

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    praw.models.Comment.edit_wrap = edit_wrap

    stopwatch = Stopwatch()

    logging.info("Monitoring active investments...")

    while not killhandler.killed:
        sess = session_maker()

        then = int(time.time()) - config.INVESTMENT_DURATION
        investment = sess.query(Investment).\
            filter(Investment.done == 0).\
            filter(Investment.time < then).\
            order_by(Investment.time.asc()).\
            first()

        if not investment:
            # Nothing matured yet; wait a bit before trying again
            time.sleep(5)
            continue

        duration = stopwatch.measure()

        investor = sess.query(Investor).filter(
            Investor.name == investment.name).one()
        net_worth = sess.\
            query(func.sum(Investment.amount)).\
            filter(and_(Investment.name == investor.name, Investment.done == 0)).\
            scalar()\
            + investor.balance

        logging.info("New mature investment: %s", investment.comment)
        logging.info(" -- by %s", investor.name)

        # Retrieve the post the user invested in (lazily, no API call)
        post = reddit.submission(investment.post)

        # Retrieve the post's current upvote count (triggers an API call)
        upvotes_now = post.ups
        investment.final_upvotes = upvotes_now

        # Updating the investor's balance
        factor = formula.calculate(upvotes_now, investment.upvotes, net_worth)
        amount = investment.amount
        balance = investor.balance

        new_balance = int(balance + (amount * factor))
        change = new_balance - balance
        profit = change - amount
        percent_str = f"{int((profit/amount)*100)}%"

        # Updating the investor's variables
        investor.completed += 1

        # Retrieve the bot's original response (lazily, no API call)
        if investment.response != "0":
            response = reddit.comment(id=investment.response)
        else:
            response = EmptyResponse()

        firm_profit = 0
        if new_balance < BALANCE_CAP:
            # If investor is in a firm and he profits,
            # 15% goes to the firm
            firm_name = ''
            if investor.firm != 0 and profit >= 0:
                firm = sess.query(Firm).\
                    filter(Firm.id == investor.firm).\
                    first()
                firm_name = firm.name

                user_profit = int(profit * ((100 - firm.tax) / 100))
                investor.balance += user_profit + amount

                firm_profit = int(profit * (firm.tax / 100))
                firm.balance += firm_profit
            else:
                investor.balance = new_balance

            # Edit the bot's response (triggers an API call)
            if profit > 0:
                logging.info(" -- profited %s", profit)
            elif profit == 0:
                logging.info(" -- broke even")
            else:
                logging.info(" -- lost %s", profit)

            edited_response = message.modify_invest_return(
                investment.amount, investment.upvotes, upvotes_now, change,
                profit, percent_str, investor.balance)
            if investor.firm != 0:
                edited_response += message.modify_firm_tax(
                    firm_profit, firm_name)

            response.edit_wrap(edited_response)
        else:
            # This investment pushed the investor's balance over the cap
            investor.balance = BALANCE_CAP

            # Edit the bot's response (triggers an API call)
            logging.info(" -- profited %s but got capped", profit)
            response.edit_wrap(
                message.modify_invest_capped(investment.amount,
                                             investment.upvotes, upvotes_now,
                                             change, profit, percent_str,
                                             investor.balance))

        investment.success = (profit > 0)
        investment.profit = profit
        investment.done = True

        sess.commit()

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Report the Reddit API call stats
        rem = int(reddit.auth.limits['remaining'])
        res = int(reddit.auth.limits['reset_timestamp'] - time.time())
        logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem,
                     res)

        sess.close()
def main():
    logging.info("Starting leaderboard...")

    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = sessionmaker(bind=engine)

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    # We will test our reddit connection here
    if not config.TEST and not utils.test_reddit_connection(reddit):
        exit()

    sess = session_maker()

    top_users = (sess.query(
        Investor.name,
        func.coalesce(Investor.balance + func.sum(Investment.amount),
                      Investor.balance).label("networth"),
    ).outerjoin(Investment,
                and_(Investor.name == Investment.name,
                     Investment.done == 0)).group_by(Investor.name).order_by(
                         desc("networth")).limit(500).all())

    top_users_text = ".|Utente|Patrimonio\n"
    top_users_text += ":-:|:-:|:-:\n"
    for i, user in enumerate(top_users):
        top_users_text += f"{i + 1}|/u/{user.name}|{formatNumber(user.networth)} M€\n"

    wiki_lead_text = wiki_lead_text_org.replace("%TOP_USERS%",
                                                top_users_text).replace(
                                                    "%LOCALTIME%", localtime)

    logging.info(" -- Updating wiki text to:")
    logging.info(wiki_lead_text)
    if not config.TEST:
        wikipage = reddit.subreddit("BancaDelMeme").wiki["leaderboardbig"]
        wikipage.edit(wiki_lead_text)

    top_poster = sess.execute(
        """
    SELECT  name,
            SUM(oc) AS coc,
            SUM(CASE OC WHEN 1 THEN final_upvotes ELSE 0 END) AS soc,
            count(*) as ct,
            sum(final_upvotes) as st
    FROM "Buyables"
    WHERE done = 1 AND time > :since
    GROUP BY name
    ORDER BY coc DESC, soc DESC, ct DESC, st DESC""",
        {"since": 1579020536},
    )

    top_oc_text = "Autore|#OC|Karma OC|Post totali|Karma totali\n"
    top_oc_text += ":-:|:-:|:-:|:-:|:-:\n"
    for poster in top_poster:
        top_oc_text += f"/u/{poster[0]}|{poster[1]}|{poster[2]:,d}|{poster[3]}|{poster[4]:,d}\n"
    oc_text = wiki_oc_text_org.replace("%TOP_OC%", top_oc_text).replace(
        "%LOCALTIME%", localtime)
    logging.info(" -- Updating wiki text to:")
    logging.info(oc_text)
    if not config.TEST:
        wikipage = reddit.subreddit("BancaDelMeme").wiki["leaderboardocbig"]
        wikipage.edit(oc_text)

    sess.commit()

    # Report the Reddit API call stats
    rem = int(reddit.auth.limits["remaining"])
    res = int(reddit.auth.limits["reset_timestamp"] - time.time())
    logging.info(" -- API calls remaining: %s, resetting in %.2fs", rem, res)

    sess.close()
Esempio n. 10
0
def main() -> None:
    """
    This is the main function that listens to new submissions
    and then posts the ATTENTION sticky comment.
    """
    logging.info("Starting submitter...")

    killhandler = KillHandler()

    engine = create_engine()
    sess_maker = scoped_session(sessionmaker(bind=engine))

    reddit = praw.Reddit(
        client_id=config.CLIENT_ID,
        client_secret=config.CLIENT_SECRET,
        username=config.USERNAME,
        password=config.PASSWORD,
        user_agent=config.USER_AGENT,
    )

    logging.info("Setting up database")
    conn = sqlite3.connect(config.POST_DBFILE)
    conn.execute("CREATE TABLE IF NOT EXISTS posts (id)")
    conn.commit()

    logging.info("Setting up Telegram connection")
    tbot = telegram.Bot(token=config.TG_TOKEN)
    try:
        tbot.get_me()
    except telegram.error.TelegramError as e_teleg:
        logging.error(e_teleg)
        logging.critical("Telegram error!")
        return

    # We will test our reddit connection here
    if not test_reddit_connection(reddit):
        return

    logging.info("Starting checking submissions...")

    stopwatch = Stopwatch()

    sess = sess_maker()

    subreddits = reddit.subreddit("+".join(config.SUBREDDITS))
    for submission in subreddits.stream.submissions(pause_after=6):
        if killhandler.killed:
            logging.info("Termination signal received - exiting")
            break
        if not submission:
            # because of pause_after
            # to handle ctr+c above
            continue

        duration = stopwatch.measure()

        logging.info("New submission: %s", submission)
        logging.info(" -- retrieved in %ss", duration)

        c = conn.cursor()
        c.execute("SELECT * FROM posts WHERE id=?", (submission.id,))
        if c.fetchone():
            logging.info("Already processed")
            continue
        post_telegram(conn, submission, tbot)

        bot_reply = post_reply(submission)

        # Measure how long processing took
        duration = stopwatch.measure()
        logging.info(" -- processed in %.2fs", duration)

        # Create Buyable
        if bot_reply:
            sess.add(
                Buyable(post=submission.id, name=submission.author.name, response=bot_reply.id)
            )
        sess.commit()
Esempio n. 11
0
def main():
    """
    This is where the magic happens. This function listens
    to all new messages in the inbox and passes them to worker
    object that decides on what to do with them.
    """
    logging.info("Starting main")

    if config.POST_TO_REDDIT:
        logging.info("Warning: Bot will actually post to Reddit!")

    logging.info("Setting up database")

    killhandler = KillHandler()
    engine = create_engine(config.DB, pool_recycle=60, pool_pre_ping=True)
    session_maker = scoped_session(sessionmaker(bind=engine))
    worker = CommentWorker(session_maker)

    while True:
        try:
            Base.metadata.create_all(engine)
            break
        except sqlalchemy.exc.OperationalError:
            logging.info("Database not available yet; retrying in 5s")
            time.sleep(5)

    logging.info("Setting up Reddit connection")

    reddit = praw.Reddit(client_id=config.CLIENT_ID,
                         client_secret=config.CLIENT_SECRET,
                         username=config.USERNAME,
                         password=config.PASSWORD,
                         user_agent=config.USER_AGENT)

    # We will test our reddit connection here
    if not utils.test_reddit_connection(reddit):
        exit()

    stopwatch = Stopwatch()

    logging.info("Listening for inbox replies...")

    while not killhandler.killed:
        # Iterate over the latest comment replies in inbox
        reply_function = reddit.inbox.comment_replies

        if config.MAINTENANCE:
            logging.info(
                "ENTERING MAINTENANCE MODE. NO OPERATIONS WILL BE PROCESSED.")
            for comment in praw.models.util.stream_generator(reply_function):
                logging.info("New comment %s:", comment)
                if comment.new:
                    comment.reply_wrap(message.MAINTENANCE_ORG)
                    comment.mark_read()

        for comment in praw.models.util.stream_generator(reply_function):
            # Measure how long since we finished the last loop iteration
            duration = stopwatch.measure()
            logging.info("New comment %s (%s):", comment, type(comment))
            logging.info(" -- retrieved in %.2fs", duration)

            if comment.new:
                if comment.subreddit.display_name.lower() in config.SUBREDDITS:
                    # Process the comment only in allowed subreddits
                    worker(comment)
                else:
                    logging.info(" -- skipping (wrong subreddit)")

                # Mark the comment as processed
                comment.mark_read()
            else:
                logging.info(" -- skipping (already processed)")

            # Measure how long processing took
            duration = stopwatch.measure()
            logging.info(" -- processed in %.2fs", duration)

            # Report the Reddit API call stats
            rem = int(reddit.auth.limits['remaining'])
            res = int(reddit.auth.limits['reset_timestamp'] - time.time())
            logging.info(" -- API calls remaining: %.2f, resetting in %.2fs",
                         rem, res)

            # Check for termination requests
            if killhandler.killed:
                logging.info("Termination signal received - exiting")
                break

            stopwatch.reset()