diff --git a/shopapi/src/main/scala/net/shop/api/Model.scala b/shopapi/src/main/scala/net/shop/api/Model.scala index 7f1e400..70836c9 100644 --- a/shopapi/src/main/scala/net/shop/api/Model.scala +++ b/shopapi/src/main/scala/net/shop/api/Model.scala @@ -6,6 +6,8 @@ import scala.util.Failure import net.shift.security.User import net.shift.security.Permissions import net.shift.security.Permission +import net.shift.loc.Language +import net.shift.io.FileSystem case class UserInfo(firstName: String, lastName: String, cnp: String, phone: String) case class CompanyInfo(name: String, cif: String, regCom: String, bank: String, bankAccount: String, phone: String) @@ -124,18 +126,18 @@ case class ServiceHit(year: Int, month: Int, day: Int, service: String) case class ServiceStat(hit: ServiceHit, count: Long) object Formatter { - def format[T: Formatter](v: T)(implicit lang: String): String = { + def format[T: Formatter](v: T)(implicit lang: Language, fs: FileSystem): String = { implicitly[Formatter[T]].write(v) } } trait Formatter[T] { - def write(value: T)(implicit lang: String): String + def write(value: T)(implicit lang: Language, fs: FileSystem): String } object ShopError { def fail(msg: String) = Failure(new ShopError(msg)) - def fail(e: Throwable) = Failure(new ShopError(e)) + def fail(msg: String, e: Throwable) = Failure(new ShopError(msg, e)) } case class ShopError(msg: String, e: Throwable) extends RuntimeException(msg, e) { diff --git a/shopdatabase/src/main/scala/net/shop/mongodb/MongoDBPersistence.scala b/shopdatabase/src/main/scala/net/shop/mongodb/MongoDBPersistence.scala index c0582e4..7761c9d 100644 --- a/shopdatabase/src/main/scala/net/shop/mongodb/MongoDBPersistence.scala +++ b/shopdatabase/src/main/scala/net/shop/mongodb/MongoDBPersistence.scala @@ -26,10 +26,10 @@ object MongoDBPersistence extends Persistence with MongoConversions { def productById(id: String): Try[ProductDetail] = try { db("products").findOne(MongoDBObject("_id" -> new ObjectId(id))) match { case Some(obj) => Success(mongoToProduct(obj)) - case _ => fail("Item " + id + " not found") + case _ => fail("no.product") } } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def allProducts: Try[Iterator[ProductDetail]] = try { @@ -37,7 +37,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { mongoToProduct(p) }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def categoryProducts(cat: String, spec: SortSpec = NoSort): Try[Iterator[ProductDetail]] = try { @@ -54,7 +54,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { mongoToProduct(p) }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def searchProducts(text: String, spec: SortSpec = NoSort): Try[Iterator[ProductDetail]] = try { @@ -65,16 +65,16 @@ object MongoDBPersistence extends Persistence with MongoConversions { mongoToProduct(p) }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def categoryById(id: String): Try[Category] = try { db("categories").findOne(MongoDBObject("_id" -> new ObjectId(id))) match { case Some(obj) => Success(mongoToCategory(obj)) - case _ => fail("Item " + id + " not found") + case _ => fail("no.category") } } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def allCategories: Try[Iterator[Category]] = try { @@ -82,14 +82,14 @@ object MongoDBPersistence extends Persistence with MongoConversions { mongoToCategory(p) }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def deleteProducts(ids: String*): Try[Int] = try { val num = (0 /: ids)((acc, id) => db("products").remove(MongoDBObject("_id" -> new ObjectId(id))).getN) Success(num) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def createProducts(prod: ProductDetail*): Try[Seq[String]] = try { @@ -97,7 +97,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { db("products").insert(mongos: _*) Success(mongos map { p => p.get("_id").getOrElse("?").toString() }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def updateProducts(prod: ProductDetail*): Try[Seq[String]] = try { @@ -116,7 +116,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { builder.execute() Success(ids) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def createCategories(cats: Category*): Try[Seq[String]] = try { @@ -124,7 +124,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { db("categories").insert(mongos: _*) Success(mongos map { p => p.getOrElse("_id", "?").toString }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def updateCategories(c: Category*): Try[Seq[String]] = try { @@ -143,14 +143,14 @@ object MongoDBPersistence extends Persistence with MongoConversions { builder.execute() Success(ids) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def deleteCategories(ids: String*): Try[Int] = try { val num = (0 /: ids)((acc, id) => db("categories").remove(MongoDBObject("_id" -> new ObjectId(id))).getN) Success(num) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def createUsers(user: UserDetail*): Try[Seq[String]] = try { @@ -158,7 +158,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { db("users").insert(mongos: _*) Success(mongos map { p => p.getOrElse("_id", "?").toString }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def updateUsers(user: UserDetail*): Try[Seq[String]] = try { @@ -177,14 +177,14 @@ object MongoDBPersistence extends Persistence with MongoConversions { builder.execute() Success(ids) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def deleteUsers(ids: String*): Try[Int] = try { val num = (0 /: ids)((acc, id) => db("users").remove(MongoDBObject("_id" -> new ObjectId(id))).getN) Success(num) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def allUsers: Try[Iterator[UserDetail]] = try { @@ -192,7 +192,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { mongoToUser(p) }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error") } def userByEmail(email: String): Try[Option[UserDetail]] = try { @@ -201,7 +201,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { case _ => Success(None) } } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def createOrder(order: OrderLog*): Try[Seq[String]] = { @@ -218,7 +218,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { Success(mongos map { _.getOrElse("_id", "?").toString }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } } @@ -226,21 +226,21 @@ object MongoDBPersistence extends Persistence with MongoConversions { val update = db("orders").update(MongoDBObject("id" -> orderId), $set(("status" -> status.index))) Success(update.getN == 1) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def ordersByEmail(email: String): Try[Iterator[OrderLog]] = try { Success( db("orders").find(MongoDBObject("email" -> email)) map mongoToOrder) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def ordersByProduct(productId: String): Try[Iterator[OrderLog]] = try { Success( db("orders").find("items.id" $in List(productId)) map mongoToOrder) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def storeServiceHit(h: ServiceHit): Try[String] = try { @@ -250,7 +250,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { Success(mongo.get("_id").getOrElse("?").toString()) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } def allServiceStats(): Try[Iterator[ServiceStat]] = try { @@ -258,7 +258,7 @@ object MongoDBPersistence extends Persistence with MongoConversions { mongoToServiceStat(p) }) } catch { - case e: Exception => fail(e) + case e: Exception => fail("internal.error", e) } } diff --git a/shopweb/localization/ro.json b/shopweb/localization/ro.json index f72b141..91894a1 100644 --- a/shopweb/localization/ro.json +++ b/shopweb/localization/ro.json @@ -1,24 +1,24 @@ [ { "code" : "100", - "name" : "no_categories", + "name" : "internal.error", + "text" : "Eroare interna" + }, + { + "code" : "100", + "name" : "no.categories", "text" : "Categoriile nu pot fi obtinute" }, { "code" : "101", - "name" : "no_category", + "name" : "no.category", "text" : "Categorie inexistenta" }, { "code" : "102", - "name" : "no_product", + "name" : "no.product", "text" : "Produs inexistent" }, - { - "code" : "103", - "name" : "add_to_cart", - "text" : "Adauga in cos" - }, { "code" : "104", "name" : "categories", diff --git a/shopweb/src/main/scala/net/shop/model/Formatters.scala b/shopweb/src/main/scala/net/shop/model/Formatters.scala index 4916c67..3cb776f 100644 --- a/shopweb/src/main/scala/net/shop/model/Formatters.scala +++ b/shopweb/src/main/scala/net/shop/model/Formatters.scala @@ -2,8 +2,10 @@ package net.shop package model import api._ -import net.shift.loc.Language import net.shop.api.ShopError +import net.shift.loc.Loc +import net.shift.loc.Language +import net.shift.io.FileSystem object Formatters { @@ -15,9 +17,9 @@ object Formatters { override def dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'") } - def write(err: ShopError)(implicit lang: String): String = { + def write(err: ShopError)(implicit lang: Language, fs: FileSystem): String = { import org.json4s.native.Serialization.writePretty - writePretty(Err(err.msg)) + writePretty(Err(Loc.loc0(lang)(err.msg).text)) } case class Err(msg: String) @@ -32,7 +34,7 @@ object Formatters { override def dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'") } - def write(orders: List[OrderLog])(implicit lang: String): String = { + def write(orders: List[OrderLog])(implicit lang: Language, fs: FileSystem): String = { import org.json4s.native.Serialization.writePretty writePretty(orders) } @@ -47,7 +49,7 @@ object Formatters { override def dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'") } - def write(user: UserDetail)(implicit lang: String): String = { + def write(user: UserDetail)(implicit lang: Language, fs: FileSystem): String = { import org.json4s.native.Serialization.writePretty writePretty(UserSummary(user.userInfo, user.companyInfo, user.email, user.addresses)) } @@ -63,7 +65,7 @@ object Formatters { override def dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'") } - def write(err: ValidationFail)(implicit lang: String): String = { + def write(err: ValidationFail)(implicit lang: Language, fs: FileSystem): String = { import org.json4s.native.Serialization.writePretty writePretty(err) } @@ -77,7 +79,7 @@ object Formatters { override def dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'") } - def write(err: FieldError)(implicit lang: String): String = { + def write(err: FieldError)(implicit lang: Language, fs: FileSystem): String = { import org.json4s.native.Serialization.writePretty writePretty(err) } @@ -91,9 +93,9 @@ object Formatters { override def dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'") } - def write(c: Category)(implicit lang: String): String = { + def write(c: Category)(implicit lang: Language, fs: FileSystem): String = { import org.json4s.native.Serialization.writePretty - writePretty(CategoryJson(c.id, c.title.getOrElse(lang, "ro"), c.position)) + writePretty(CategoryJson(c.id, c.title.getOrElse(lang.name, "ro"), c.position)) } case class CategoryJson(id: Option[String], title: String, position: Int) diff --git a/shopweb/src/main/scala/net/shop/utils/ShopUtils.scala b/shopweb/src/main/scala/net/shop/utils/ShopUtils.scala index c050c70..60d02c3 100644 --- a/shopweb/src/main/scala/net/shop/utils/ShopUtils.scala +++ b/shopweb/src/main/scala/net/shop/utils/ShopUtils.scala @@ -18,7 +18,7 @@ object ShopUtils { def imagePath(variant: String, prod: ProductDetail): String = prod.images match { case h :: _ => s"/data/products/${prod.stringId}/$variant/${h}" - case Nil => "/static/images/noimage.png" + case Nil => "" } def errorTag(text: String) =
{ text }
diff --git a/shopweb/src/main/scala/net/shop/web/pages/CategoryPage.scala b/shopweb/src/main/scala/net/shop/web/pages/CategoryPage.scala index dc5a21e..f3e9613 100644 --- a/shopweb/src/main/scala/net/shop/web/pages/CategoryPage.scala +++ b/shopweb/src/main/scala/net/shop/web/pages/CategoryPage.scala @@ -5,7 +5,6 @@ import scala.util.Failure import scala.util.Success import scala.xml._ import scala.xml._ - import net.shift._ import net.shift._ import net.shift.engine.http._ @@ -17,6 +16,7 @@ import net.shift.template.Binds._ import net.shift.template.Snippet._ import net.shop.utils.ShopUtils._ import net.shop.web.ShopApplication +import net.shop.api.ShopError object CategoryPage extends Cart[Request] { self => @@ -36,10 +36,11 @@ object CategoryPage extends Cart[Request] { self => case "div" attributes HasClasses("info_tag_text" :: _, a) / _ =>
{ cat.title_?(s.state.lang.name) }
% a }) match { case Success(n) => n + case Failure(ShopError(msg, _)) => errorTag(Loc.loc0(s.state.lang)(msg).text) case Failure(f) => errorTag(f toString) } } - case Failure(t) =>
{ Loc.loc0(s.state.lang)("no_categories").text }
+ case Failure(t) =>
{ Loc.loc0(s.state.lang)("no.categories").text }
} Success(s.state.initialState, prods.toSeq) diff --git a/shopweb/src/main/scala/net/shop/web/pages/OrderPage.scala b/shopweb/src/main/scala/net/shop/web/pages/OrderPage.scala index 581020b..24a2cf1 100644 --- a/shopweb/src/main/scala/net/shop/web/pages/OrderPage.scala +++ b/shopweb/src/main/scala/net/shop/web/pages/OrderPage.scala @@ -23,6 +23,8 @@ import net.shop.api.Person import net.shop.api.Company import net.shop.api.Address import net.shift.io.IODefaults +import net.shift.loc.Loc +import net.shop.api.ShopError object OrderPage extends DynamicContent[OrderState] with Selectors with IODefaults { @@ -99,6 +101,7 @@ object OrderPage extends DynamicContent[OrderState] with Selectors with IODefaul case "td" attributes HasClass("c4", a) / _ => % a }) match { case Success(n) => acc ++ n + case Failure(ShopError(msg, _)) => acc ++ errorTag(Loc.loc0(s.state.lang)(msg).text) case Failure(f) => acc ++ errorTag(f toString) } case Failure(f) => errorTag(f getMessage) diff --git a/shopweb/src/main/scala/net/shop/web/pages/ProductDetailPage.scala b/shopweb/src/main/scala/net/shop/web/pages/ProductDetailPage.scala index f4806de..42a2f96 100644 --- a/shopweb/src/main/scala/net/shop/web/pages/ProductDetailPage.scala +++ b/shopweb/src/main/scala/net/shop/web/pages/ProductDetailPage.scala @@ -22,11 +22,10 @@ import net.shift.loc.Language import net.shift.common.ShiftFailure import net.shift.security.User import net.shift.common.Config +import net.shop.api.ShopError object ProductDetailPage extends Cart[ProductPageState] { - val noImage = "/static/images/noimage.png" - override def snippets = List(meta, catlink, productLink, images, detailPrice, stock, details, specs, customize, edit) ++ super.snippets val meta = reqSnip("fb_meta") { @@ -45,17 +44,18 @@ object ProductDetailPage extends Cart[ProductPageState] { for { n <- fb } yield { (ProductPageState(s.state.initialState.req, Success(prod), s.state.user), n) } + case Failure(ShopError(msg, _)) => ShiftFailure(Loc.loc0(s.state.lang)(msg).text).toTry case Failure(t) => - Success(s.state.initialState, errorTag(Loc.loc0(s.state.lang)("no_product").text)) + ShiftFailure(Loc.loc0(s.state.lang)("no.product").text).toTry } - case _ => Success(s.state.initialState, errorTag(Loc.loc0(s.state.lang)("no_product").text)) + case _ => ShiftFailure(Loc.loc0(s.state.lang)("no.product").text).toTry } } } def pageTitle(s: PageState[ProductPageState]) = s.initialState.product match { case Success(prod) => prod.title_?(s.lang.name) - case Failure(t) => Loc.loc0(s.lang)("no_product").text + case Failure(t) => "" } val catlink = reqSnip("catlink") { @@ -87,28 +87,33 @@ object ProductDetailPage extends Cart[ProductPageState] { val images = reqSnip("images") { s => (s.state.initialState.product flatMap { prod => - bind(s.node) { + prod.images match { + case Nil => Success(s.state.initialState, NodeSeq.Empty) + case images => + bind(s.node) { + + case "b:img" attributes a => - case "b:img" attributes a => + val p = imagePath(prod.stringId, "normal", prod.images.head) + val large = imagePath(prod.stringId, "large", prod.images.head) - val p = if (prod.images.isEmpty) noImage else imagePath(prod.stringId, "normal", prod.images.head) - val large = if (prod.images.isEmpty) noImage else imagePath(prod.stringId, "large", prod.images.head) + node("img", a.attrs.attrs + ("src" -> p) + ("title" -> prod.title_?(s.state.lang.name)) + ("data-zoom-image" -> large)) - node("img", a.attrs.attrs + ("src" -> p) + ("title" -> prod.title_?(s.state.lang.name)) + ("data-zoom-image" -> large)) + case e attributes HasId("thumb", a) => + NodeSeq.fromSeq(for { + p <- prod.images zipWithIndex + } yield { + val normal = imagePath(prod.stringId, "normal", p._1) + val large = imagePath(prod.stringId, "large", p._1) + val thumb = imagePath(prod.stringId, "thumb", p._1) + (node(e, a.attrs - "id") / + + ).e + }) - case e attributes HasId("thumb", a) => - NodeSeq.fromSeq(for { - p <- prod.images zipWithIndex - } yield { - val normal = imagePath(prod.stringId, "normal", p._1) - val large = imagePath(prod.stringId, "large", p._1) - val thumb = imagePath(prod.stringId, "thumb", p._1) - (node(e, a.attrs - "id") / - - ).e - }) + } map { b => (ProductPageState(s.state.initialState.req, Success(prod), s.state.user), b) } + } - } map { b => (ProductPageState(s.state.initialState.req, Success(prod), s.state.user), b) } }).recover { case _ => (s.state.initialState, NodeSeq.Empty) } } diff --git a/shopweb/src/main/scala/net/shop/web/pages/ProductsPage.scala b/shopweb/src/main/scala/net/shop/web/pages/ProductsPage.scala index f489835..d7c5909 100644 --- a/shopweb/src/main/scala/net/shop/web/pages/ProductsPage.scala +++ b/shopweb/src/main/scala/net/shop/web/pages/ProductsPage.scala @@ -29,6 +29,7 @@ import net.shift.common.XmlUtils._ import net.shift.common.NodeOps._ import net.shift.engine.page.Html5 import net.shift.common.Path +import net.shop.api.ShopError object ProductsPage extends Cart[Request] { @@ -77,7 +78,7 @@ object ProductsPage extends Cart[Request] { case Failure(f) => errorTag(f toString) } } - case Failure(t) => errorTag(Loc.loc0(s.state.lang)("no_category").text) + case Failure(t) => errorTag(Loc.loc0(s.state.lang)("no.category").text) } Success((s.state.initialState, prods.toSeq)) } @@ -93,7 +94,8 @@ object ProductsPage extends Cart[Request] { Success((s.state.initialState, e / NodeSeq.fromSeq(v))) case _ => Success((s.state.initialState, NodeSeq.Empty)) } - case Failure(t) => Success((s.state.initialState, errorTag(Loc.loc0(s.state.lang)("no_category").text))) + case Failure(ShopError(msg, _)) => Success((s.state.initialState, errorTag(Loc.loc0(s.state.lang)(msg).text))) + case Failure(t) => Success((s.state.initialState, errorTag(Loc.loc0(s.state.lang)("no.category").text))) } } diff --git a/shopweb/src/main/scala/net/shop/web/services/CategoryService.scala b/shopweb/src/main/scala/net/shop/web/services/CategoryService.scala index da94f1d..8a36af9 100644 --- a/shopweb/src/main/scala/net/shop/web/services/CategoryService.scala +++ b/shopweb/src/main/scala/net/shop/web/services/CategoryService.scala @@ -37,6 +37,7 @@ import net.shift.io.IO import net.shift.io.FileSystem import net.shift.io.FileOps import net.shop.utils.ShopUtils._ +import net.shop.api.ShopError object CategoryService extends Selectors with TraversingSpec @@ -53,9 +54,10 @@ object CategoryService extends Selectors ShopApplication.persistence.categoryById(id) match { case scala.util.Success(cat) => fs.deletePath(Path(s"${dataPath}/categories/$id")) - implicit val l = r.language.name + implicit val l = r.language service(_(JsonResponse(Formatter.format(cat)))) - case scala.util.Failure(t) => service(_(Resp.notFound)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) + case scala.util.Failure(t) => service(_(Resp.notFound)) } } @@ -68,7 +70,8 @@ object CategoryService extends Selectors case scala.util.Success(num) => fs.deletePath(Path(s"${dataPath}/categories/$id")); service(_(Resp.ok)) - case scala.util.Failure(t) => service(_(Resp.notFound)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) + case scala.util.Failure(t) => service(_(Resp.notFound)) } } @@ -88,11 +91,14 @@ object CategoryService extends Selectors } service(_(Resp.created)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) case scala.util.Failure(t) => service(_(Resp.serverError.asText.withBody("category.create.fail"))) } - case (_, Invalid(msgs)) => validationFail(msgs)(r.language.name) + case (_, Invalid(msgs)) => + implicit val l = r.language + validationFail(msgs) } @@ -113,13 +119,16 @@ object CategoryService extends Selectors IO.arrayProducer(f._2)(FileOps.writer(Path(s"${dataPath}/categories/${p.head}.png"))) } service(_(Resp.created)) + + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) case scala.util.Failure(t) => error("Cannot create category ", t) service(_(Resp.serverError)) } - case (_, Invalid(msgs)) => validationFail(msgs)(r.language.name) - + case (_, Invalid(msgs)) => + implicit val l = r.language + validationFail(msgs) } } diff --git a/shopweb/src/main/scala/net/shop/web/services/FormValidation.scala b/shopweb/src/main/scala/net/shop/web/services/FormValidation.scala index adc15b7..58926c0 100644 --- a/shopweb/src/main/scala/net/shop/web/services/FormValidation.scala +++ b/shopweb/src/main/scala/net/shop/web/services/FormValidation.scala @@ -20,6 +20,7 @@ import net.shop.model.FieldError import net.shop.model.Formatters.ValidationErrorWriter import net.shop.model.ValidationFail import net.shop.web.ShopApplication +import net.shift.io.FileSystem object FormImplicits extends IODefaults { implicit val o = new Ordering[Double] { @@ -171,12 +172,12 @@ trait FormValidation extends IODefaults { case _ => None } - def validationFail(msgs: ValidationFail)(implicit lang: String) = + def validationFail(msgs: ValidationFail)(implicit lang: Language, fs: FileSystem) = service(r => { r(JsonResponse(Formatter.format(msgs)).code(403)) }) - def respValidationFail(resp: net.shift.engine.http.AsyncResponse, msgs: ValidationFail)(implicit lang: String) = + def respValidationFail(resp: net.shift.engine.http.AsyncResponse, msgs: ValidationFail)(implicit lang: Language, fs: FileSystem) = resp(JsonResponse(Formatter.format(msgs)).code(403)) } diff --git a/shopweb/src/main/scala/net/shop/web/services/OrderService.scala b/shopweb/src/main/scala/net/shop/web/services/OrderService.scala index 48a2894..39f328a 100644 --- a/shopweb/src/main/scala/net/shop/web/services/OrderService.scala +++ b/shopweb/src/main/scala/net/shop/web/services/OrderService.scala @@ -126,7 +126,8 @@ object OrderService extends HttpPredicates with FormValidation with TraversingSp } } case Invalid(msgs) => - respValidationFail(resp, msgs)(r.language.name) + implicit val l = r.language + respValidationFail(resp, msgs) } case Failure(t) => @@ -152,7 +153,7 @@ object OrderService extends HttpPredicates with FormValidation with TraversingSp import model.Formatters._ - implicit val l = r.language.name + implicit val l = r.language ShopApplication.persistence.ordersByEmail(email) match { case Success(orders) => resp(JsonResponse(Formatter.format(orders.toList))) @@ -168,7 +169,7 @@ object OrderService extends HttpPredicates with FormValidation with TraversingSp id <- param("productid") } yield service(resp => { import model.Formatters._ - implicit val l = r.language.name + implicit val l = r.language ShopApplication.persistence.ordersByProduct(id) match { case Success(orders) => resp(JsonResponse(Formatter.format(orders.toList))) diff --git a/shopweb/src/main/scala/net/shop/web/services/ProductService.scala b/shopweb/src/main/scala/net/shop/web/services/ProductService.scala index d391f3a..85ce286 100644 --- a/shopweb/src/main/scala/net/shop/web/services/ProductService.scala +++ b/shopweb/src/main/scala/net/shop/web/services/ProductService.scala @@ -38,6 +38,7 @@ import net.shift.io.FileSystem import net.shift.io.FileOps import net.shift.io.IO import utils.ShopUtils._ +import net.shop.api.ShopError object ProductService extends ShiftUtils with Selectors @@ -55,7 +56,8 @@ object ProductService extends ShiftUtils case scala.util.Success(num) => fs.deletePath(Path(s"${dataPath}/products/$id")) service(_(Resp.ok)) - case scala.util.Failure(t) => service(_(Resp.notFound)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) + case scala.util.Failure(t) => service(_(Resp.notFound)) } } @@ -69,25 +71,23 @@ object ProductService extends ShiftUtils case (files, Valid(o)) => val cpy = o.copy(images = Set(files.map(f => f._2): _*).toList) - ShopApplication.persistence.productById(pid) match { - case scala.util.Success(p) => - val merged = cpy.copy(images = p.images ++ cpy.images) - - ShopApplication.persistence.updateProducts(merged) match { - case scala.util.Success(p) => - files.map { f => - IO.arrayProducer(f._3)(FileOps.writer(Path(s"${dataPath}/products/${p.head}/${f._1}"))) - } - service(_(Resp.created)) - case scala.util.Failure(t) => - error("Cannot create product ", t) - service(_(Resp.serverError)) - } - - case scala.util.Failure(f) => service(_(Resp.notFound)) + (for { + p <- ShopApplication.persistence.productById(pid) + u <- ShopApplication.persistence.updateProducts(cpy.copy(images = p.images ++ cpy.images)) + } yield { + files.map { f => + IO.arrayProducer(f._3)(FileOps.writer(Path(s"${dataPath}/products/${u.head}/${f._1}"))) + } + service(_(Resp.created)) + }) match { + case scala.util.Success(s) => s + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) + case scala.util.Failure(t) => service(_(Resp.serverError)) } - case (_, Invalid(msgs)) => validationFail(msgs)(r.language.name) + case (_, Invalid(msgs)) => + implicit val l = r.language + validationFail(msgs) } } @@ -116,17 +116,17 @@ object ProductService extends ShiftUtils IO.arrayProducer(f._3)(FileOps.writer(Path(s"${dataPath}/products/${p.head}/${f._1}"))) }) { d => log.debug("Write files: " + d) } } - log.debug("Send OK") service(_(Resp.created)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) case scala.util.Failure(t) => error("Cannot create product ", t) - log.debug("Send ERROR") service(_(Resp.serverError)) } case (_, Invalid(msgs)) => log.debug("Send FAIL") - validationFail(msgs)(r.language.name) + implicit val l = r.language + validationFail(msgs) } @@ -181,8 +181,9 @@ object ProductService extends ShiftUtils case p => Valid(p) }) } catch { - case e: Exception => e.printStackTrace() - (Nil, Invalid(ValidationFail(FieldError("edit_discount_price", Loc.loc0(loc)("field.discount.smaller").text)))) + case e: Exception => + e.printStackTrace() + (Nil, Invalid(ValidationFail(FieldError("edit_discount_price", Loc.loc0(loc)("field.discount.smaller").text)))) } } diff --git a/shopweb/src/main/scala/net/shop/web/services/SettingsService.scala b/shopweb/src/main/scala/net/shop/web/services/SettingsService.scala index 14ef60b..eadb36e 100644 --- a/shopweb/src/main/scala/net/shop/web/services/SettingsService.scala +++ b/shopweb/src/main/scala/net/shop/web/services/SettingsService.scala @@ -29,6 +29,7 @@ import net.shop.api.OrderStatus import scala.util.Success import scala.util.Failure import net.shift.security.Permission +import net.shop.api.ShopError object SettingsService extends Selectors with TraversingSpec @@ -42,8 +43,9 @@ object SettingsService extends Selectors u <- permissions(Loc.loc0(r.language)("user.not.found").text, Permission("write")) } yield { ShopApplication.persistence.updateOrderStatus(orderId, OrderStatus.fromIndex(status.toInt)) match { - case Success(_) => service(_(Resp.ok)) - case Failure(msg) => service(_(Resp.notFound.asText.withBody(Loc.loc(r.language)("order.not.found", List(orderId)).text))) + case Success(_) => service(_(Resp.ok)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) + case Failure(msg) => service(_(Resp.notFound.asText.withBody(Loc.loc(r.language)("order.not.found", List(orderId)).text))) } } @@ -68,7 +70,8 @@ object SettingsService extends Selectors case _ => service(_(Resp.serverError.asText.withBody(Loc.loc0(r.language)("login.fail").text))) } service(_(Resp.created.asText.withBody(Loc.loc0(r.language)("settings.saved").text))) - case Invalid(e) => validationFail(e)(r.language.name) + case Invalid(e) => + validationFail(e) } case None => service(_(Resp.forbidden.asText.withBody(Loc.loc0(r.language)("login.fail").text))) } diff --git a/shopweb/src/main/scala/net/shop/web/services/ShopServices.scala b/shopweb/src/main/scala/net/shop/web/services/ShopServices.scala index bb5f038..ba3f62f 100644 --- a/shopweb/src/main/scala/net/shop/web/services/ShopServices.scala +++ b/shopweb/src/main/scala/net/shop/web/services/ShopServices.scala @@ -50,6 +50,7 @@ import net.shift.common.State import net.shift.engine.http.Header import net.shift.common.Config import utils.ShopUtils._ +import net.shop.api.ShopError trait ShopServices extends ShiftUtils with Selectors with TraversingSpec with DefaultLog with SecuredService with IODefaults { @@ -151,7 +152,9 @@ trait ShopServices extends ShiftUtils with Selectors with TraversingSpec with De u <- user } yield { val logout = !r.param("logout").isEmpty - Html5.pageFromFile(PageState(f(r, u), r.language, if (logout) None else u), filePath, snipets)(bySnippetAttr[T], fs) + val p = Html5.pageFromFile(PageState(f(r, u), r.language, if (logout) None else u), filePath, snipets)(bySnippetAttr[T], fs) + + p } def productsVariantImages = for { @@ -183,6 +186,7 @@ trait ShopServices extends ShiftUtils with Selectors with TraversingSpec with De Html5.runPageFromFile(PageState(CartState(index, item, prod), r.language), Path("web/templates/cartitem.html"), CartItemNode).map(_._2 toString) }) match { case Success(list) => resp(JsonResponse(write(list))) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) case Failure(t) => log.error("Failed processing cart ", t) resp(JsonResponse(write(Nil))) diff --git a/shopweb/src/main/scala/net/shop/web/services/UserService.scala b/shopweb/src/main/scala/net/shop/web/services/UserService.scala index ffd13fb..d76bcac 100644 --- a/shopweb/src/main/scala/net/shop/web/services/UserService.scala +++ b/shopweb/src/main/scala/net/shop/web/services/UserService.scala @@ -34,6 +34,7 @@ import net.shop.model.FieldError import net.shift.html.Valid import net.shift.html.Invalid import net.shift.common.Config +import net.shop.api.ShopError object UserService extends Selectors with TraversingSpec @@ -50,8 +51,9 @@ object UserService extends Selectors } yield { ShopApplication.persistence.userByEmail(user.name) match { case Success(Some(ud)) => - implicit val l = r.language.name + implicit val l = r.language service(_(JsonResponse(Formatter.format(ud)))) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) case _ => service(_(Resp.notFound.asText.withBody(Loc.loc(r.language)("user.not.found", Seq(user.name)).text))) } @@ -88,8 +90,8 @@ object UserService extends Selectors cnp = u.cnp, phone = u.phone) - val perms = List("read") ++ (if (Config.string("admin.user") == u.email) List("write") else Nil ) - + val perms = List("read") ++ (if (Config.string("admin.user") == u.email) List("write") else Nil) + val usr = UserDetail(id = None, userInfo = ui, companyInfo = CompanyInfo("", "", "", "", "", ""), @@ -101,12 +103,14 @@ object UserService extends Selectors ShopApplication.persistence.createUsers(usr) match { case scala.util.Success(ids) => service(_(Resp.created)) + case scala.util.Failure(ShopError(msg, _)) => service(_(Resp.ok.asText.withBody(Loc.loc0(r.language)(msg).text))) case scala.util.Failure(t) => error("Cannot create user ", t) service(_(Resp.serverError.withBody(Loc.loc0(r.language)("user.cannot.create").text))) } - case Invalid(msgs) => validationFail(msgs)(r.language.name) + case Invalid(msgs) => + validationFail(msgs) } } diff --git a/shopweb/web/static/css/style.css b/shopweb/web/static/css/style.css index c374cb2..21b2884 100755 --- a/shopweb/web/static/css/style.css +++ b/shopweb/web/static/css/style.css @@ -562,6 +562,7 @@ h1 { float: left; margin-left: 20px; margin-top: 20px; + margin-right: 10px; font-size: 18px; } diff --git a/shopweb/web/templates/productquickview.html b/shopweb/web/templates/productquickview.html index 95146c1..8bd18e2 100644 --- a/shopweb/web/templates/productquickview.html +++ b/shopweb/web/templates/productquickview.html @@ -26,7 +26,6 @@ -