Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add product api #166

Merged
merged 3 commits into from
May 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions ShopApp.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions ShopApp/Data/API/Adapters/MagentoImageAdapter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// MagentoImageAdapter.swift
// ShopApp
//
// Created by Radyslav Krechet on 5/2/18.
// Copyright © 2018 RubyGarage. All rights reserved.
//

import ShopApp_Gateway

struct MagentoImageAdapter {
private static let imagePathNoSelection = "no_selection"
private static let defaultCatalogPath = "pub/media/catalog/product"
private static let mediaTypeImage = "image"

static func adapt(_ imagePath: String) -> Image? {
guard imagePath != imagePathNoSelection, let src = buildSrc(with: BaseRouter.hostUrl, catalogPath: defaultCatalogPath, imagePath: imagePath) else {
return nil
}

let image = Image()
image.id = src
image.src = src

return image
}

static func adapt(_ response: GalleryEntryResponse) -> Image? {
guard response.mediaType == mediaTypeImage, let src = buildSrc(with: BaseRouter.hostUrl, catalogPath: defaultCatalogPath, imagePath: response.file) else {
return nil
}

let image = Image()
image.id = String(response.id)
image.src = src
image.imageDescription = response.label

return image
}

private static func buildSrc(with hostUrl: String?, catalogPath: String, imagePath: String) -> String? {
guard let hostUrl = hostUrl else {
return nil
}

return hostUrl + catalogPath + imagePath
}
}
81 changes: 81 additions & 0 deletions ShopApp/Data/API/Adapters/MagentoProductAdapter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// MagentoProductAdapter.swift
// ShopApp
//
// Created by Radyslav Krechet on 4/30/18.
// Copyright © 2018 RubyGarage. All rights reserved.
//

import ShopApp_Gateway

struct MagentoProductAdapter {
private static let customAttributeDescriptionCode = "description"
private static let customAttributeThumbnailCode = "thumbnail"
private static let customAttributeImageCode = "image"

static func adapt(_ response: GetProductResponse, currency: String, paginationValue: Int? = nil) -> Product {
let product = Product()
product.id = response.sku
product.title = response.name
product.price = Decimal(response.price)
product.currency = currency
product.discount = ""
product.images = []
product.type = String(response.attributeSetId)
product.vendor = ""
product.createdAt = response.createdAt
product.updatedAt = response.updatedAt
product.tags = []
product.variants = []
product.options = []

if let paginationValue = paginationValue {
product.paginationValue = String(paginationValue)
}

if let descriptionValue = response.customAttributes.filter({ $0.attributeCode == customAttributeDescriptionCode }).first?.value.data {
product.productDescription = descriptionValue.htmlToString
product.additionalDescription = descriptionValue
}

var customAttributeImages: [Image] = []

if let thumbnailValue = response.customAttributes.filter({ $0.attributeCode == customAttributeThumbnailCode }).first?.value.data, let thumbnail = MagentoImageAdapter.adapt(thumbnailValue) {
customAttributeImages.append(thumbnail)
}

if let imageValue = response.customAttributes.filter({ $0.attributeCode == customAttributeImageCode }).first?.value.data, let image = MagentoImageAdapter.adapt(imageValue) {
customAttributeImages.append(image)
}

guard let mediaGalleryEntries = response.mediaGalleryEntries else {
product.images = customAttributeImages

return product
}

let mediaGalleryImages = mediaGalleryEntries.flatMap { MagentoImageAdapter.adapt($0) }
let productVariant = ProductVariant()
productVariant.id = response.sku
productVariant.title = response.name
productVariant.price = Decimal(response.price)
productVariant.available = true
productVariant.image = customAttributeImages.first ?? mediaGalleryImages.first
productVariant.selectedOptions = []
productVariant.productId = response.sku

product.images = mediaGalleryImages
product.variants?.append(productVariant)

return product
}
}

private extension String {
var htmlToAttributedString: NSAttributedString? {
return try? NSAttributedString(data: Data(utf8), options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
}
var htmlToString: String {
return htmlToAttributedString?.string ?? ""
}
}
130 changes: 124 additions & 6 deletions ShopApp/Data/API/Alamofire/MagentoAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import Alamofire
import ShopApp_Gateway

public class MagentoAPI: BaseAPI, API {
private let defaultBaseUrl = "rest/V1/"
private let defaultPaginationValue = 1
private let createdAtField = "created_at"
private let attributeSetIdField = "attribute_set_id"
private let nameField = "name"
private let searchValueFormat = "%%%@%%"
private let typeIdField = "type_id"
private let simpleValue = "simple"
private let unauthorizedStatusCode = 401
private let sessionService = SessionService()

Expand All @@ -19,7 +27,8 @@ public class MagentoAPI: BaseAPI, API {
- Parameter shopDomain: Domain of shop
*/
public init(shopDomain: String) {
BaseRouter.baseUrl = shopDomain
BaseRouter.hostUrl = shopDomain
BaseRouter.baseUrl = defaultBaseUrl

super.init()
}
Expand All @@ -28,40 +37,99 @@ public class MagentoAPI: BaseAPI, API {

public func getShopInfo(callback: @escaping RepoCallback<Shop>) {
// There is no api to fetch terms
callback(nil, nil)
}

// MARK: - Products

public func getProductList(perPage: Int, paginationValue: Any?, sortBy: SortingValue?, keyPhrase: String?, excludePhrase: String?, reverse: Bool, callback: @escaping RepoCallback<[Product]>) {
// TODO: Implement api method
guard let sortBy = sortBy, sortBy.rawValue != SortingValue.popular.rawValue else {
callback([], nil)

return
}

var currentPaginationValue = defaultPaginationValue
let builder = ProductsParametersBuilder()

if sortBy.rawValue == SortingValue.createdAt.rawValue {
_ = builder.addSortOrderParameters(field: createdAtField, isRevers: reverse)
} else if sortBy.rawValue == SortingValue.type.rawValue, let keyPhrase = keyPhrase {
_ = builder.addFilterParameters(field: attributeSetIdField, value: keyPhrase)

if let excludePhrase = excludePhrase {
_ = builder.addFilterParameters(field: nameField, value: excludePhrase, condition: .notEqual)
}
}

if let paginationValue = paginationValue as? String, let castedPaginationValue = Int(paginationValue) {
currentPaginationValue = castedPaginationValue
}

getProductList(perPage: perPage, paginationValue: currentPaginationValue, builder: builder, callback: callback)
}

public func getProduct(id: String, callback: @escaping RepoCallback<Product>) {
// TODO: Implement api method
getStoreConfigs { [weak self] (сurrency, error) in
guard let strongSelf = self else {
return
}

guard error == nil, let сurrency = сurrency else {
callback(nil, error ?? ContentError())

return
}

let route = MagentoProductsRoute.getProduct(sku: id)
let request = MagentoProductsRouter(route: route)

strongSelf.execute(request) { (response, error) in
guard error == nil, let json = response as? [String: Any], let response = GetProductResponse.object(from: json) else {
callback(nil, error ?? ContentError())

return
}

callback(MagentoProductAdapter.adapt(response, currency: сurrency), nil)
}
}
}

public func searchProducts(perPage: Int, paginationValue: Any?, searchQuery: String, callback: @escaping RepoCallback<[Product]>) {
// TODO: Implement api method
var currentPaginationValue = defaultPaginationValue
let builder = ProductsParametersBuilder()
.addFilterParameters(field: nameField, value: String(format: searchValueFormat, arguments: [searchQuery]), condition: .like)

if let paginationValue = paginationValue as? String, let castedPaginationValue = Int(paginationValue) {
currentPaginationValue = castedPaginationValue
}

getProductList(perPage: perPage, paginationValue: currentPaginationValue, builder: builder, callback: callback)
}

// MARK: - Categories

public func getCategoryList(perPage: Int, paginationValue: Any?, sortBy: SortingValue?, reverse: Bool, callback: @escaping RepoCallback<[ShopApp_Gateway.Category]>) {
// TODO: Implement api method
callback([], nil)
}

public func getCategoryDetails(id: String, perPage: Int, paginationValue: Any?, sortBy: SortingValue?, reverse: Bool, callback: @escaping RepoCallback<ShopApp_Gateway.Category>) {
// TODO: Implement api method
callback(nil, nil)
}

// MARK: - Articles

public func getArticleList(perPage: Int, paginationValue: Any?, sortBy: SortingValue?, reverse: Bool, callback: @escaping RepoCallback<[Article]>) {
// TODO: Implement api method
// There is no api to fetch articles
callback([], nil)
}

public func getArticle(id: String, callback: @escaping RepoCallback<(article: Article, baseUrl: URL)>) {
// TODO: Implement api method
// There is no api to fetch article
callback(nil, nil)
}

// MARK: - Customer
Expand Down Expand Up @@ -531,4 +599,54 @@ public class MagentoAPI: BaseAPI, API {
sessionService.removeData()
}
}

private func getProductList(perPage: Int, paginationValue: Int, builder: ProductsParametersBuilder, callback: @escaping RepoCallback<[Product]>) {
getStoreConfigs { [weak self] (сurrency, error) in
guard let strongSelf = self else {
return
}

guard error == nil, let сurrency = сurrency else {
callback(nil, error ?? ContentError())

return
}

let parameters = builder
.addFilterParameters(field: strongSelf.typeIdField, value: strongSelf.simpleValue)
.addPaginationParameters(pageSize: perPage, currentPage: paginationValue)
.build()

let route = MagentoProductsRoute.getProducts(parameters: parameters)
let request = MagentoProductsRouter(route: route)

strongSelf.execute(request) { (response, error) in
guard error == nil, let json = response as? [String: Any], let response = GetProductListResponse.object(from: json) else {
callback(nil, error ?? ContentError())

return
}

let nextPaginationValue = response.nextPaginationValue(perPage: perPage, currentPaginationValue: paginationValue)
let products = response.items.map { MagentoProductAdapter.adapt($0, currency: сurrency, paginationValue: nextPaginationValue) }

callback(products, nil)
}
}
}

private func getStoreConfigs(callback: @escaping RepoCallback<String>) {
let route = MagentoStoreRoute.getConfigs
let request = MagentoStoreRouter(route: route)

execute(request) { (response, error) in
guard error == nil, let json = response as? [Any], let response = StoreConfigResponse.objects(from: json) else {
callback(nil, error ?? ContentError())

return
}

callback(response.first?.сurrencyСode ?? "", nil)
}
}
}
Loading