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))
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( '👋 Все Ваши данные удалены, бот больше не будет Вас беспокоить')
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)
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)
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> добавлен в список.')
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]])
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))
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)
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))
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()
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))
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} удален из списка')
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))
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()
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()