Example #1
0
def action_catalog_category(query, data):
    user = get_user(query.from_user.id, session)
    category_id = data['id']

    if category_id is None:
        product_ids = session.query(
            UserProduct.product_id).filter_by(user_id=user.id).distinct()
        products = session.query(Product).filter(
            Product.id.in_(product_ids), Product.catalog_category_ids == '{}')

        for product in products:
            query.message.reply_html(get_product_card(product),
                                     reply_markup=get_product_markup(
                                         user.id, product))

    else:
        rows = get_catalog(session, user.id, data['level'], category_id)

        if len(rows) < 2:
            product_ids = session.query(
                UserProduct.product_id).filter_by(user_id=user.id).distinct()
            products = session.query(Product).filter(
                Product.id.in_(product_ids),
                Product.catalog_category_ids.any(category_id))
            for product in products:
                query.message.reply_html(get_product_card(product),
                                         reply_markup=get_product_markup(
                                             user.id, product))

        else:
            return query.message.reply_html(
                '🗂️ Категории:', reply_markup=get_catalog_markup(rows))
Example #2
0
def logout(update, context):
    user = get_user(update.message.from_user.id, session)

    session.query(UserProduct).filter_by(user_id=user.id).delete()
    session.delete(user)
    session.commit()

    update.message.reply_html(
        '👋 Все Ваши данные удалены, бот больше не будет Вас беспокоить')
Example #3
0
def products_list_all(update, context):
    user = get_user(update.message.from_user.id, session)

    product_ids = session.query(
        UserProduct.product_id).filter_by(user_id=user.id).distinct()
    products = session.query(Product).filter(
        Product.id.in_(product_ids)).distinct()

    return products_list(update, context, user, products)
Example #4
0
def product_list_by_notify(update, context, is_notify):
    user = get_user(update.message.from_user.id, session)

    product_ids = session.query(UserProduct.product_id).filter_by(
        user_id=user.id).join(UserProduct.settings).filter(
            UserProductSettings.is_price_notify == is_notify).distinct()

    products = session.query(Product).filter(
        Product.id.in_(product_ids)).distinct()

    return products_list(update, context, user, products)
Example #5
0
def message_add_product(update, context):
    user = get_user(update.message.from_user.id, session)
    matches = re.findall(env.PRODUCT_REGEXP, update.message.text)

    if matches:
        parsed_uri = parse.urlparse(matches[0])
    else:
        return

    domain = parsed_uri.netloc.split('.')[-1]
    code = int("".join(filter(lambda c: c.isdigit(), parsed_uri.path)))

    product = Product.get_product(domain, code, session)
    user_product = session.query(UserProduct).filter_by(
        user_id=user.id, product_id=product.id).first()

    if user_product:
        return update.message.reply_text('Вы уже отслеживаете этот товар')

    if session.query(UserProduct).filter_by(
            user_id=user.id).count() >= user.max_product_count:
        return update.message.reply_text(
            f'Вы отслеживаете максимально допустимое количество товаров: {user.max_product_count})'
        )

    session.add(
        UserProduct(user_id=user.id,
                    product_id=product.id,
                    settings=UserProductSettings(),
                    price=UserProductPrice()))

    product.ref_count += 1
    session.commit()

    # todo move to rmq. make class that returns channel
    connection = pika.BlockingConnection(rmq.get_url_parameters())
    channel = connection.channel()

    channel.basic_publish(exchange=env.RMQ_EXCHANGE,
                          routing_key=env.RMQ_QUEUE_NEW_PRODUCT,
                          body=json.dumps({
                              'user_id': user.id,
                              'product_id': product.id
                          }),
                          properties=pika.BasicProperties(delivery_mode=2))

    return update.message.reply_html(
        f'✅ Товар <a href="{code}">{product.url}</a> добавлен в список.')
Example #6
0
def get_product_markup(user_id, product):
    user_product = session.query(UserProduct).filter_by(
        user_id=user_id, product_id=product.id).first()

    delete_button = InlineKeyboardButton('❌ Удалить',
                                         callback_data=json.dumps({
                                             'action':
                                             'delete_product',
                                             'product_id':
                                             product.id
                                         }))
    price_button = InlineKeyboardButton('📈 Цены',
                                        callback_data=json.dumps({
                                            'action':
                                            'prices_history',
                                            'product_id':
                                            product.id
                                        }))
    notify_button = InlineKeyboardButton(
        '🔕 Отключить уведомления'
        if user_product.settings.is_price_notify else '🔔 Включить уведомления',
        callback_data=json.dumps({
            'action': 'price_notify',
            'product_id': product.id,
            'n': user_product.settings.is_price_notify
        }))

    return InlineKeyboardMarkup([[delete_button, price_button],
                                 [notify_button]])
Example #7
0
def action_brand_list(query, data):
    brand_id = data['brand_id']
    user = get_user(query.from_user.id, session)

    products = session.query(Product).filter(
        and_(
            Product.id.in_([
                user_product.product_id for user_product in user.user_products
            ]), Product.brand_id == brand_id))

    for product in products:
        query.message.reply_html(get_product_card(product),
                                 reply_markup=get_product_markup(
                                     user.id, product))
Example #8
0
def message_any(update, context):
    if context.user_data.get('action') == 'search':
        context.user_data['action'] = None
        user = get_user(update.message.from_user.id, session)

        products_ids = session.query(
            UserProduct.product_id).filter_by(user_id=user.id).distinct()

        q = '%' + update.message.text + '%'
        products = session.query(Product)\
            .filter(and_(or_(Product.name.ilike(q), Brand.title.ilike(q)), Product.id.in_(products_ids)))\
            .join(Brand, Product.brand_id == Brand.id)\
            .all()

        if not products:
            update.message.reply_text('Совпадений не найдено')

        for product in products:
            update.message.reply_html(get_product_card(product),
                                      reply_markup=get_product_markup(
                                          user.id, product))
    else:
        return menu.menu_item_select(update, context)
Example #9
0
def brands_list(update, context):
    user = get_user(update.message.from_user.id, session)
    user_product_ids = session.query(
        UserProduct.product_id).filter_by(user_id=user.id).distinct()

    group = session.query(Brand.title, Brand.id, func.count(Product.brand_id)) \
        .join(Product, Product.brand_id == Brand.id) \
        .filter(Product.id.in_(user_product_ids)) \
        .group_by(Brand.title, Brand.id, Product.brand_id) \
        .order_by(Brand.title.asc())

    buttons = []
    for brand_title, brand_id, count in group:
        buttons.append([
            InlineKeyboardButton(f'{brand_title}: {count}',
                                 callback_data=json.dumps({
                                     'action': 'brand_list',
                                     'brand_id': brand_id
                                 }))
        ])

    update.message.reply_html('👓 Бренды:',
                              reply_markup=InlineKeyboardMarkup(buttons))
Example #10
0
def check_prices(context):
    user_product_prices = session.query(UserProductPrice).filter(
        UserProductPrice.status.in_([
            UserProductPrice.STATUS_APPEARED, UserProductPrice.STATUS_UPDATED
        ])).join(
            UserProductSettings, UserProductPrice.user_product_id ==
            UserProductSettings.user_product_id).filter(
                UserProductSettings.is_price_notify == True).all()

    for user_product_price in user_product_prices:
        product = user_product_price.user_product.product
        user_product = user_product_price.user_product

        diff_perc = abs(user_product_price.price_start - user_product_price.
                        price_end) / user_product_price.price_start * 100

        price_icon = get_price_icon(user_product_price.price_end,
                                    user_product_price.price_start)
        cur_price = ProductPrice.format_price_value(
            user_product_price.price_end, product.domain)
        prev_price = ProductPrice.format_price_value(
            user_product_price.price_start, product.domain)

        if prev_price == cur_price:
            price_text = cur_price
        else:
            price_text = f'{prev_price} → {cur_price}'

        text = f'⚠️ Обновилась цена на {product.header}\n\n{price_icon} {price_text}'

        if product.size_list:
            text += '\n' + get_size_list(product)

        reply_markup = get_product_markup(user_product.user.id, product)
        context.job_queue.run_once(notify_user,
                                   1,
                                   context={
                                       'telegram_id':
                                       user_product.user.telegram_id,
                                       'text': text,
                                       'reply_markup': reply_markup
                                   })

        user_product_price.status = UserProductPrice.STATUS_PROCESSED
        user_product_price.price_start = user_product_price.price_end

    session.commit()
Example #11
0
def action_price_notify(query, data):
    user = get_user(query.from_user.id, session)
    user_product = session.query(UserProduct).filter_by(
        user_id=user.id, product_id=data['product_id']).first()

    if not user_product:
        return

    user_product.settings.is_price_notify = not data['n']
    session.commit()

    if user_product.settings.is_price_notify:
        text = f'🔔 Включены уведомления для {user_product.product.header}'
    else:
        text = f'🔕 Отключены уведомления для {user_product.product.header}'

    return query.message.reply_html(text,
                                    reply_markup=get_product_markup(
                                        user.id, product=user_product.product))
Example #12
0
def action_delete_product(query, data):
    user = get_user(query.from_user.id, session)
    product_id = data['product_id']

    product = session.query(Product).filter_by(id=product_id).first()
    user_product = session.query(UserProduct).filter_by(
        user_id=user.id, product_id=product_id).first()

    if user_product:
        session.query(UserProductSettings).filter_by(
            user_product_id=user_product.id).delete()
        session.query(UserProduct).filter_by(user_id=user.id,
                                             product_id=product_id).delete()
        session.query(UserProductPrice).filter_by(
            user_id=user.id, product_id=product_id).delete()
        product.ref_count -= 1
        session.commit()
    else:
        return query.message.reply_text('❗ Товар не найден')

    return query.message.reply_html(
        f'❌ Товар {product.header} удален из списка')
Example #13
0
def action_prices_history(query, data):
    user = get_user(query.from_user.id, session)

    product = session.query(Product).filter_by(id=data['product_id']).first()
    product_prices = product.prices[:30]

    text = f'📈 Цены на {product.header}\n\n'

    if not product_prices:
        text += 'нет данных'

    for product_price in product_prices:
        price_icon = get_price_icon(product_price.value,
                                    product_price.prev_value)
        price_value = ProductPrice.format_price_value(product_price.value,
                                                      product.domain)

        text += f'{product_price.created_at.date()}  {price_icon} {price_value}\n'

    return query.message.reply_html(text,
                                    reply_markup=get_product_markup(
                                        user.id, product))
Example #14
0
from scrapy.crawler import CrawlerProcess
from scrapy.settings import Settings

from common.models import Product
from common.session import session
from wbscrapy.project.spiders.products_spider import ProductsSpider

settings = Settings()
settings.setmodule('wbscrapy.project.settings', priority='project')
process = CrawlerProcess(settings)

offset = 0
batch_size = process.settings.get('CONCURRENT_REQUESTS', 16) * 100

while True:
    products = session.query(Product).limit(batch_size).offset(offset).all()

    if not products:
        break

    process.crawl(ProductsSpider, products, session)
    offset += batch_size

process.start()
Example #15
0
    global q_len

    try:
        data = json.loads(body.decode('utf-8'))
        product_ids.append(data['product_id'])
    except json.JSONDecodeError:
        pass

    q_len -= 1
    if not q_len:
        ch.stop_consuming()


if q_len:
    channel.basic_consume(queue=env.RMQ_QUEUE_NEW_PRODUCT,
                          on_message_callback=message_callback,
                          auto_ack=True)
    channel.start_consuming()

connection.close()

products = session.query(Product).filter(Product.id.in_(
    set(product_ids))).all()

if products:
    settings = Settings()
    settings.setmodule('wbscrapy.project.settings', priority='project')
    process = CrawlerProcess(settings)
    process.crawl(ProductsSpider, products, session)
    process.start()