# LaTiendaCOOP backend This README aims to document functionality of backend as well as required steps to get it up and running. ## Table of Contents - [First Steps](#first-steps) - [Load location data](#load-location-data) - [Load taxonomy data](#load-taxonomy-data) - [Company Endpoints](#company-endpoints) - [Product Endpoints](#product-endpoints) - [Core Endpoints](#core-endpoints) - [History Endpoints](#history-endpoints) - [Stats Endpoints](#stats-endpoints) - [Shop Integrations](#shop-integrations) - [WooCommerce](#woocommerce) - [Product Search](#product-search) - [Massive Data Load Endpoints](#massive-data-load-endpoints) - [COOP and Managing User Data Load](#coop-and-managing-user-data-load) - [Product Data Load](#product-data-load) - [GeoIP Setup](#geoip-setup) - [Tags](#tags) - [Development Utils](#development-utils) - [Fake product data generation](#fake-product-data-generation) ## First Steps - Clone repository: `git clone git@bitbucket.org:enreda/back-latienda.git` - Use docker image for Postgis ``` docker run --name postgis -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -d -p 5432:5432 postgis/postgis ``` - Create file `.env` from `example.env` and populate fields correctly From inside the project's folder: - Make migrations: ``` python manage.py makemigrations core geo companies products history stats python manage.py migrate ``` - Start server in development mode: `python manage.py runserver` ### Load Location Data To load initial location data use: `python manage.py loadgisdata` ### Load Taxonomy Data This data serves as initial Tags To load initial set of tags: `python manage.py addtaxonomy` ## Company Endpoints ### CompanyViewSet Queryset: validated Company instances only Permissions: - anon user: safe methods - auth user: full access where user is company creator ### MyCompanyViewSet Queryset: Company instances where user is creator Permissions: - anon user: no access - auth user: full access ### AdminCompanyViewSet Queryset: all Company instances, validated or not Permissions: only accesible to authenticated users with role `SITE_ADMIN` ### random_company_sample Method view that returns a randome sample of companies By default it returns 6 instances, but can be customized through parameter `size` ## Product Endpoints ### ProductViewSet Endpoint url: `/api/v1/products/` Queryset: active Product instances only Permissions: - anon user: safe methods - auth user: full access where user is product creator ### MyProductsViewSet Endpoint url: `/api/v1/my_products/` Queryset: Product instances where user is creator Permissions: - anon user: no access - auth user: full access ### AdminProductsViewSet Endpoint url: `/api/v1/admin_products/` Queryset: all Product instances, acgtive or not Permissions: only accesible to authenticated users with role `SITE_ADMIN` ### load_coop_products [POST] Endpoint url: `/api/v1/load_products/` Method view that reads a CSV file. ### product_search [GET] Endpoint url: `/api/v1/search_products/` Allows searching of Products to all users Parameters: - q: used for search [MANDATORY] - limit: max number of returned instances [OPTIONAL] - offset: where to start counting results [OPTIONAL] - shipping_cost: true/false - discount: true/false - category: string - tags: string - order: string (newest/oldest) - price_min: int - price_max: int ### purchase_email [POST] Endpoint url: `/api/v1/purchase_email/` Sends email to company manager about the product that the user wants to purchase, and sends confirmation email to user. Parameters: - email: mandatory for anonymous users - telephone - company - product - comment ## Core Endpoints ### CustomUserViewSet Endpoint url: `/api/v1/users/` Queryset: all CustomUser instances Permissions: - anon user: only POST to register new user - auth user: no access - admin user: full access ### ChangeUserPasswordView Ednpoint url: `/api/v1/user/change_password//` Permissions: only accessible for your own user instance ### UpdateUserView Endpoint url: `/api/v1/user/update/` Permissions: only accessible for your own user instance ### create_company_user [POST] Edndpoint: `/api/v1/create_company_user/` Simultaneously create a company and its related user NOT WORKING!!! ### my_user [GET] Endpoint url: `/api/v1/my_user/` Returns instance of authenticated user ### load_coop_managers [POST] Ednpoint url: `/api/v1/load_coops/` For each row it creates a Company instance, and a user instance linked to the company, with role `COOP_MANAGER` ### activate_user Endpoint: `/activate///` This endpoint is reached from the URL sent to the user after their registration ### User Management Creation: - endpoint: `/api/v1/users/` - method: GET - payload: ```json { "email": "test@email.com", "full_name": "TEST NAME", "password": "VENTILADOR2ES1234499.89", } ``` Change password: - endpoint: api/v1/user/change_password/{user.pk}/ - method: POST - payload: ```json { "old_password": "my_old_password", "password": "SUPERSECRETNEWPASSWORD", "password2": "SUPERSECRETNEWPASSWORD" } ``` Update user profile: - endpoint: api/v1/users// - method: PUT - payload: ```json { "email": "new_user@email.com", "full_name": "Mr. TEST NAME", } ``` ### Authentication Implemented using `djangorestframework-simplejwt` New token pair endpoint: `/api/v1/token/` Response: ```json { "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMjI3MTcwNSwianRpIjoiZDU4YTgzYzFkYzFkNDI5MTljMGQ0NzcxNzljNzUxYTQiLCJ1c2VyX2lkIjo4fQ.yln80W5lONSyHwwqF4qBBHteqLuRfdLLWuaQANr_vxc", "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyMTg4OTA1LCJqdGkiOiIzNGIxMzM3NmU4MWI0OWY5YjU3ZmUxM2M5NThmZWZkYiIsInVzZXJfaWQiOjh9.aRDCUvKj7LCvixjPLC9ghy0h7rfRwR6Lo3A7HX4kSHE" } ``` Refresh expired token endpoint: `/api/v1/token/refresh/` ### Users Endpoint url: `/api/v1/users/` To get info on authenticated user: `/api/v1/my_user/` Authenticated users cannot create new users User are active by default To create user: ```json { "email": "test_user23@mail.com", "full_name": "Mr Test User", "password": "wqertewqr32qrewqr", "provider": "TWITTER" } ``` ## History Endpoints Endpoint url: `/api/v1/history/`: Historical records about product importation ## Stats Endpoints Endpoint url: `/api/v1/stats/` logs about user interaction with products links ## Location Endpoints Location ednpoints: - `/api/v1/countries/` - `/api/v1/regions/` - `/api/v1/provinces/` - `/api/v1/cities/` Tables filled with data from `datasets/gadm36_ESP.gpkg` with `loadgisdata` command. ## Shop Integrations We provide integrations with online shop platforms It requires the json field `Company.credentials` to have the appropiate format and values Endoint: `/api/v1/companies/{PK}/import_products/` The software to handle different platform imports can be found in `utils` ### WooCommerce Credential format: ```json { "key": "qwerweqr", "secret": "asdfsa", } ``` Method: `utils.woocommerce.migrate_shop_products` ## Product Search Endpoint: `/api/v1/product_search/` Query parameters: - `q`: text from the search input box Response format: ```json { "filters": { "tags": { "singles": ["tag1", "tag2"], // for tags that aren't nested "entry_1": ["subtag_1", "subtag_2"], // for tree tags like entry_1/subtag_1 "entry_2": ["subtag_1", "subtag_2"] // one per penultimate tag in tree }, "attributes": { "singles": ["tag1", "tag2"], // for tags that aren't nested "entry_1": ["subtag_1", "subtag_2"], // for tree tags like entry_1/subtag_1 "entry_2": ["subtag_1", "subtag_2"] // one per penultimate tag in tree }, }, "products" : [], // list of serialized instances, in order of relevancy } ``` Available query parameters: - q: used for search [MANDATORY] - limit: max number of returned instances [OPTIONAL] - offset: where to start counting results [OPTIONAL] - shipping_cost: true/false - discount: true/false - category: string - tags: string - order: string (newest/oldest) Check out `products.tests.ProductSearchTest` for a practical case. ## Massive Data Load Endpoints ### COOP and Managing User Data Load For massive load of data from COOPs and the managing user. CSV headers: `email,cif,nombre-coop,nombre-corto,url,es-tienda` Only admin users have access to endoint ### Product Data Load Endpoint: `/api/v1/load_products/` Only functional for users with a related company instance For massive load of product data. CSV headers: `sku,nombre-producto,descripcion,imagen,url,precio,gastos-envio,cond-envio,descuento,stock,tags,categoria,identificadores` Number fields must not include other symbols (like currency) ## GeoIP Setup Module: `geoip2` - Download the `GeoLite2 City` and `GeoLite2 Country` binary datasets from maxmind.com - Unzip files into `datasets/` folder - Set `settings.GEOIP_PATH` to datasets folder Optional: - install `libmaxminddb` C library for improved performance: `sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin` ## Tags Both `Company` and `Product` models make use of tags. ### Load shopping taxonomy To create the initial set of tags, we can use the `addtaxonomy` management command. Reads the data from `datasets/shop-taxonomy.es-ES.txt` which is from google shopping ### Top-level tags In order to extract the top level tags for use as categories, we can use the `extractparenttas` management command. It saves the results to `datasets/top_tags.txt` ## Development Utils ### Fake product data generation To create a dataset of fake companies and products: `python manage.py addtestdata` Creates 10 Companies, with 10 products each. WARNING: the script deletes existing instances of both Company and Product