diff --git a/api/__init__.py b/api/__init__.py index 8bdb24b..d8e5390 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -17,8 +17,9 @@ db = SQLAlchemy(app) # eSales esales = Cluster(app.config.get("ESALES_URL")) -from api.views import designers +from api.views import designers, categories app.register_blueprint(designers.mod) +app.register_blueprint(categories.mod) def check_authentication(): diff --git a/api/helpers.py b/api/helpers.py new file mode 100644 index 0000000..bd3bed1 --- /dev/null +++ b/api/helpers.py @@ -0,0 +1,26 @@ +# coding=UTF-8 +import unidecode +import re + + +def slugify(text): + """Converts a string to a human-readable url""" + + # translate + text = unidecode.unidecode(text) + + # lowercase + text = text.lower() + + # replace unwanted chars + numbers = re.compile('(?<=\d),(?=\d)') + text = numbers.sub('', text) + unwanted_chars = re.compile(r'[^_a-z0-9/]+') + text = unwanted_chars.sub('_', text) + + # remove redundant _ + duplicated_underscores = re.compile('_{2,}') + text = duplicated_underscores.sub('_', text) + text = text.strip('_') + + return text diff --git a/api/models/__init__.py b/api/models/__init__.py index 7759767..596ca08 100644 --- a/api/models/__init__.py +++ b/api/models/__init__.py @@ -1 +1,2 @@ from .designer import Designer +from .category import Category diff --git a/api/models/category.py b/api/models/category.py new file mode 100644 index 0000000..a55d895 --- /dev/null +++ b/api/models/category.py @@ -0,0 +1,74 @@ +from api import db +from api.helpers import slugify + + +class Category(db.Model): + __tablename__ = 'categories' + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(255), nullable=False) + texts = db.relationship( + 'CategoryTexts', backref='category', lazy='dynamic') + + def path(self, locale='sv_SE'): + row = CategoryTreeI18n.query.filter_by( + category_id=self.id, locale=locale).first() + if not row: + raise Exception( + 'Could not find a path for category: {}, locale: {}'.format(self.id, locale)) + path = row.path.replace('rot/', '', 1) + path = slugify(path) + return path + + def to_json(self, nested=False): + j = { + 'id': self.id, + 'name': self.name + } + if nested: + j['texts'] = [t.to_json() for t in self.texts] + + return j + + +class CategoryTexts(db.Model): + __tablename__ = 'category_texts' + + id = db.Column(db.Integer, primary_key=True) + category_id = db.Column(db.Integer, db.ForeignKey('categories.id')) + locale = db.relationship("Locale") + locale_id = db.Column(db.Integer, db.ForeignKey('locales.id')) + wallpaper_name = db.Column(db.String(250)) + wallpaper_h1 = db.Column(db.String(250)) + wallpaper_description = db.Column(db.Text) + canvas_name = db.Column(db.String(250)) + canvas_h1 = db.Column(db.String(250)) + canvas_description = db.Column(db.Text) + design_wallpaper_name = db.Column('name', db.String(250)) + design_wallpaper_h1 = db.Column(db.String(250)) + design_wallpaper_description = db.Column(db.Text) + + def to_json(self): + return { + 'id': self.id, + 'locale': self.locale.value, + 'wallpaper_name': self.wallpaper_name, + 'wallpaper_h1': self.wallpaper_h1, + 'wallpaper_description': self.wallpaper_description, + 'canvas_name': self.canvas_name, + 'canvas_h1': self.canvas_h1, + 'canvas_description': self.canvas_description, + 'design_wallpaper_name': self.design_wallpaper_name, + 'design_wallpaper_h1': self.design_wallpaper_h1, + 'design_wallpaper_description': self.design_wallpaper_description, + } + + +class CategoryTreeI18n(db.Model): + __tablename__ = 'v_categorytree_i18n' + + category_id = db.Column('id', db.Integer) + path = db.Column(db.String(250)) + locale = db.Column(db.String(250)) + + __table_args__ = (db.PrimaryKeyConstraint(category_id, locale),) diff --git a/api/models/locale.py b/api/models/locale.py index 3a2d557..50eb93d 100644 --- a/api/models/locale.py +++ b/api/models/locale.py @@ -5,10 +5,7 @@ class Locale(db.Model): __tablename__ = 'locales' id = db.Column(db.Integer, primary_key=True) - value = db.Column(db.String(5), nullable=False) + value = db.Column(db.String(5)) - def to_json(self): - return { - "id": self.id, - "value": self.value - } + def __repr__(self): + return self.value diff --git a/api/tasks/esales.py b/api/tasks/esales.py index 74f22eb..3446a3d 100644 --- a/api/tasks/esales.py +++ b/api/tasks/esales.py @@ -26,3 +26,24 @@ def update_designer(designer): directory = app.config.get("ESALES_IMPORT_DIR") importfile.write(directory) + + +def update_category(category): + importfile = ImportFile() + for text in category.texts: + locale = text.locale + tree = CategoryTree("categories_{}".format(locale.value)) + tree.add_category(Category( + key='root/{}'.format(category.path(locale.value)), + display_name=category.name, + wallpaper_description=text.wallpaper_description, + wallpaper_h1=text.wallpaper_h1, + canvas_description=text.canvas_description, + canvas_h1=text.canvas_h1, + design_wallpaper_description=text.design_wallpaper_description, + design_wallpaper_h1=text.design_wallpaper_h1 + )) + importfile.add_operation("update", tree) + + directory = app.config.get("ESALES_IMPORT_DIR") + importfile.write(directory) diff --git a/api/views/categories.py b/api/views/categories.py new file mode 100644 index 0000000..8ed9b8f --- /dev/null +++ b/api/views/categories.py @@ -0,0 +1,29 @@ +from flask import Blueprint, request, jsonify +from api import db, tasks +from api.models import Category + +mod = Blueprint('categories', __name__, url_prefix='/categories') + + +@mod.route("/", methods=["GET"]) +def list(): + categories = Category.query.all() + return jsonify(categories=[c.to_json() for c in categories]) + + +@mod.route("/", methods=["GET"]) +def show(id): + category = Category.query.get_or_404(id) + return jsonify(category.to_json(nested=True)) + + +@mod.route("/", methods=["PUT"]) +def update(id): + category = Category.query.get_or_404(id) + data = request.json + for k, v in data.items(): + setattr(category, k, v) + db.session.add(category) + db.session.commit() + tasks.esales.update_category(category) + return jsonify(category.to_json()) diff --git a/requirements.txt b/requirements.txt index 193ff06..7eca425 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ Flask-Script==2.0.5 Jinja2==2.8 MarkupSafe==0.23 SQLAlchemy==1.0.12 +Unidecode==0.04.19 Werkzeug==0.11.8 itsdangerous==0.24 psycopg2==2.6.1 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 0000000..309be1e --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,20 @@ +# coding=UTF-8 + +import unittest2 +from api.helpers import slugify + + +class TestHelpers(unittest2.TestCase): + + def test_slugify(self): + self.assertEqual(slugify('HELLO'), 'hello') + self.assertEqual(slugify('this is a test'), 'this_is_a_test') + self.assertEqual(slugify('___This is a test___'), 'this_is_a_test') + self.assertEqual(slugify('this-is-a-test'), 'this_is_a_test') + self.assertEqual(slugify('this_is_a__test'), 'this_is_a_test') + self.assertEqual(slugify('404'), '404') + self.assertEqual(slugify('1,000 reasons you are #1'), + '1000_reasons_you_are_1') + self.assertEqual(slugify('Nín hǎo'), 'nin_hao') + self.assertEqual(slugify('räksmörgås'), 'raksmorgas') + self.assertEqual(slugify('RÄKSMÖRGÅS'), 'raksmorgas')