Add variants to Teespring API

master
Nikola Forró 6 years ago
parent c9a137a9a9
commit 37a2ddec7e

@ -3,6 +3,9 @@ FROM python:alpine
WORKDIR /app WORKDIR /app
COPY . . COPY . .
RUN apk add --no-cache gcc libc-dev libxml2-dev libxslt-dev && \
rm -rf /var/cache/apk/*
RUN pip install --no-cache-dir --requirement requirements.txt RUN pip install --no-cache-dir --requirement requirements.txt
RUN addgroup -g 9999 lilia RUN addgroup -g 9999 lilia

@ -9,7 +9,7 @@ import flask_restful.reqparse
import sqlalchemy import sqlalchemy
import sqlalchemy.engine import sqlalchemy.engine
from db import db, Product from db import db, Product, Variant
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -53,6 +53,13 @@ product_fields = {
'image_url': flask_restful.fields.String(), 'image_url': flask_restful.fields.String(),
} }
variant_fields = {
'id': flask_restful.fields.Integer(),
'color': flask_restful.fields.String(),
'front_url': flask_restful.fields.String(),
'back_url': flask_restful.fields.String(),
}
filter_parser = flask_restful.reqparse.RequestParser() filter_parser = flask_restful.reqparse.RequestParser()
filter_parser.add_argument('filter', type=str) filter_parser.add_argument('filter', type=str)
@ -102,8 +109,47 @@ class ProductsResource(flask_restful.Resource):
return products, 200, {'X-Total-Count': count} return products, 200, {'X-Total-Count': count}
class VariantResource(flask_restful.Resource):
@flask_restful.marshal_with(variant_fields)
def get(self, product_id, id):
q = db.session.query(Variant).filter(Variant.product_id == product_id, Variant.id == id)
variant = q.first()
if not variant:
flask_restful.abort(404, message='Variant {0} does not exist'.format(id))
return variant, 200
class VariantsResource(flask_restful.Resource):
@flask_restful.marshal_with(variant_fields)
def get(self, product_id):
args = filter_parser.parse_args()
q = db.session.query(Variant).filter(Variant.product_id == product_id)
if args['filter']:
q = q.filter(Variant.color.ilike('%{}%'.format(args['filter'])))
count = q.count()
if args['sort_order'] == 'random':
q = q.order_by(sqlalchemy.func.random())
elif args['sort_by']:
col = getattr(Variant, args['sort_by'], None)
if col:
if args['sort_order']:
order_by = getattr(col, args['sort_order'], None)
if order_by:
q = q.order_by(order_by())
else:
q = q.order_by(col)
if args['page_size']:
q = q.limit(args['page_size'])
if args['page_number'] and args['page_size']:
q = q.offset(args['page_number'] * args['page_size'])
variants = q.all()
return variants, 200, {'X-Total-Count': count}
api.add_resource(ProductResource, '/products/<int:id>') api.add_resource(ProductResource, '/products/<int:id>')
api.add_resource(ProductsResource, '/products') api.add_resource(ProductsResource, '/products')
api.add_resource(VariantResource, '/products/<int:product_id>/variants/<int:id>')
api.add_resource(VariantsResource, '/products/<int:product_id>/variants')
if __name__ == '__main__': if __name__ == '__main__':

@ -15,3 +15,14 @@ class Product(db.Model):
days_left = db.Column(db.Integer) days_left = db.Column(db.Integer)
url = db.Column(db.String) url = db.Column(db.String)
image_url = db.Column(db.String) image_url = db.Column(db.String)
variants = db.relationship('Variant', backref='product')
class Variant(db.Model):
__tablename__ = 'variants'
id = db.Column(db.Integer, primary_key=True)
product_id = db.Column(db.Integer, db.ForeignKey('products.id'), primary_key=True)
color = db.Column(db.String)
front_url = db.Column(db.String)
back_url = db.Column(db.String)

@ -2,4 +2,5 @@ Flask
Flask-APScheduler Flask-APScheduler
Flask-RESTful Flask-RESTful
Flask-SQLAlchemy Flask-SQLAlchemy
pyquery
requests-futures requests-futures

@ -1,7 +1,7 @@
import datetime import datetime
import os import os
from db import Product from db import Product, Variant
from teespring import Teespring from teespring import Teespring
@ -42,6 +42,18 @@ class Sync(object):
product.days_left = cls._get(prod, 'days_left') product.days_left = cls._get(prod, 'days_left')
product.url = cls._get(prod, 'url') product.url = cls._get(prod, 'url')
product.image_url = cls._get(prod, 'image_url') product.image_url = cls._get(prod, 'image_url')
for var in cls._get(prod, 'variants'):
color_id = cls._get(var, 'color_id')
q = db.session.query(Variant).filter(
Variant.id == color_id,
Variant.product_id == id)
variant = q.first()
if not variant:
variant = Variant(id=color_id)
variant.front_url = cls._get(var, 'front_url')
variant.back_url = cls._get(var, 'back_url')
variant.color = cls._get(var, 'color_value')
product.variants.append(variant)
db.session.add(product) db.session.add(product)
db.session.commit() db.session.commit()
app.logger.info('Synchronization of products completed') app.logger.info('Synchronization of products completed')

@ -2,6 +2,7 @@ import json
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
from pyquery import PyQuery as pq
from requests_futures.sessions import FuturesSession from requests_futures.sessions import FuturesSession
@ -12,6 +13,22 @@ class Teespring(object):
def __init__(self, store_name): def __init__(self, store_name):
self.store_name = store_name self.store_name = store_name
def _parse_variants(self, pid, html):
result = []
d = pq(html)
for div in d('div.image_stack__container[data-visible-to-buyer="true"][data-product-id="{0}"]'.format(pid)).items():
color_id = div.attr('data-color-id')
front_url = div.find('div[data-side="front"]').find('img').eq(0).attr('data-original')
back_url = div.find('div[data-side="back"]').find('img').eq(0).attr('data-original')
li = d('li.product__color_list_item[data-product-id="{0}"][data-color-id="{1}"]'.format(pid, color_id)).eq(0)
color_value = li.find('div').eq(0).attr('style').split(':')[1]
result.append(dict(
color_id=color_id,
front_url=front_url,
back_url=back_url,
color_value=color_value))
return result
def fetch_products(self): def fetch_products(self):
session = FuturesSession() session = FuturesSession()
def get_products(page): def get_products(page):
@ -19,6 +36,7 @@ class Teespring(object):
params = dict(page=page) params = dict(page=page)
return session.get(url, params=params, headers={'Accept': 'application/json'}) return session.get(url, params=params, headers={'Accept': 'application/json'})
result = [] result = []
requests = []
page = 1 page = 1
while True: while True:
request = get_products(page) request = get_products(page)
@ -28,10 +46,16 @@ class Teespring(object):
data = r.json() data = r.json()
for product in data.get('products', []): for product in data.get('products', []):
product['url'] = BASE_URL + product['url'] product['url'] = BASE_URL + product['url']
requests.append(session.get(product['url']))
result.append(product) result.append(product)
next_url = data.get('next') next_url = data.get('next')
if not next_url: if not next_url:
break break
q = parse_qs(urlparse(next_url).query) q = parse_qs(urlparse(next_url).query)
page = q.get('page', [])[0] page = q.get('page', [])[0]
for product, request in zip(result, requests):
q = parse_qs(urlparse(product['url']).fragment)
pid = q.get('pid', [])[0]
r = request.result()
product['variants'] = self._parse_variants(pid, r.text)
return result return result

Loading…
Cancel
Save