This is an automated email from the ASF dual-hosted git repository. sergeykamov pushed a commit to branch NLPCRAFT-319 in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
commit 69f665a207b18e8d4f3b2b2b8b6b7bbbc6b1c888 Author: Sergey Kamov <skhdlem...@gmail.com> AuthorDate: Mon May 17 19:05:45 2021 +0300 WIP. --- nlpcraft/src/main/resources/sql/create_schema.sql | 27 +- nlpcraft/src/main/resources/sql/drop_schema.sql | 2 - .../org/apache/nlpcraft/common/util/NCUtils.scala | 44 +++- .../model/tools/embedded/NCEmbeddedResult.java | 5 + .../model/tools/test/NCTestClientBuilder.java | 1 + .../probe/mgrs/nlp/NCProbeEnrichmentManager.scala | 13 + .../probe/mgrs/nlp/impl/NCRequestImpl.scala | 15 +- .../nlpcraft/server/company/NCCompanyManager.scala | 22 +- .../apache/nlpcraft/server/mdo/NCCompanyMdo.scala | 1 + .../nlpcraft/server/mdo/NCCompanyPropertyMdo.scala | 41 --- .../nlpcraft/server/mdo/NCQueryStateMdo.scala | 4 +- .../org/apache/nlpcraft/server/mdo/NCUserMdo.scala | 7 +- .../nlpcraft/server/mdo/NCUserPropertyMdo.scala | 41 --- .../nlpcraft/server/probe/NCProbeManager.scala | 28 +- .../server/proclog/NCProcessLogManager.scala | 3 + .../nlpcraft/server/query/NCQueryManager.scala | 29 ++- .../nlpcraft/server/rest/NCBasicRestApi.scala | 191 ++++++++------ .../apache/nlpcraft/server/sql/NCSqlManager.scala | 284 ++++++++------------- .../nlpcraft/server/user/NCUserManager.scala | 22 +- .../apache/nlpcraft/server/rest/NCRestSpec.scala | 3 + openapi/nlpcraft_swagger.yml | 8 +- sql/mysql/drop_schema.sql | 2 - sql/mysql/schema.sql | 29 +-- sql/oracle/drop_schema.sql | 16 -- sql/oracle/schema.sql | 33 +-- sql/postgres/drop_schema.sql | 2 - sql/postgres/schema.sql | 33 +-- 27 files changed, 335 insertions(+), 571 deletions(-) diff --git a/nlpcraft/src/main/resources/sql/create_schema.sql b/nlpcraft/src/main/resources/sql/create_schema.sql index 570e215..1965ca0 100644 --- a/nlpcraft/src/main/resources/sql/create_schema.sql +++ b/nlpcraft/src/main/resources/sql/create_schema.sql @@ -30,6 +30,7 @@ CREATE TABLE nc_company ( postal_code VARCHAR, auth_token VARCHAR NOT NULL, -- Unique. auth_token_hash VARCHAR NOT NULL, -- Unique. + properties_gzip VARCHAR NULL, created_on TIMESTAMP NOT NULL, last_modified_on TIMESTAMP NOT NULL ) WITH "template=replicated, atomicity=transactional"; @@ -38,18 +39,6 @@ CREATE INDEX nc_company_idx_1 ON nc_company(name); CREATE INDEX nc_company_idx_2 ON nc_company(auth_token); CREATE INDEX nc_company_idx_3 ON nc_company(auth_token_hash); -DROP TABLE IF EXISTS nc_company_property; -CREATE TABLE nc_company_property ( - id LONG PRIMARY KEY, - company_id LONG NOT NULL, -- Foreign key nc_company.id. - property VARCHAR NOT NULL, - value VARCHAR NULL, - created_on TIMESTAMP NOT NULL, - last_modified_on TIMESTAMP NOT NULL -) WITH "template=replicated, atomicity=transactional"; - -CREATE INDEX nc_company_property_idx_1 ON nc_company_property(company_id); - DROP TABLE IF EXISTS nc_user; CREATE TABLE nc_user ( id LONG PRIMARY KEY, @@ -61,6 +50,7 @@ CREATE TABLE nc_user ( last_name VARCHAR NULL, is_admin BOOL NOT NULL, passwd_salt VARCHAR NULL, + properties_gzip VARCHAR NULL, created_on TIMESTAMP NOT NULL, last_modified_on TIMESTAMP NOT NULL ) WITH "template=replicated, atomicity=transactional"; @@ -69,18 +59,6 @@ CREATE INDEX nc_user_idx_1 ON nc_user(email); CREATE INDEX nc_user_idx_2 ON nc_user(company_id, ext_id); CREATE INDEX nc_user_idx_3 ON nc_user(company_id); -DROP TABLE IF EXISTS nc_user_property; -CREATE TABLE nc_user_property ( - id LONG PRIMARY KEY, - user_id LONG NOT NULL, -- Foreign key nc_user.id. - property VARCHAR NOT NULL, - value VARCHAR NULL, - created_on TIMESTAMP NOT NULL, - last_modified_on TIMESTAMP NOT NULL -) WITH "template=replicated, atomicity=transactional"; - -CREATE INDEX nc_user_property_idx_1 ON nc_user_property(user_id); - DROP TABLE IF EXISTS passwd_pool; CREATE TABLE passwd_pool ( id LONG PRIMARY KEY, @@ -103,6 +81,7 @@ CREATE TABLE proc_log ( cancel_tstamp TIMESTAMP NULL, res_type VARCHAR NULL, res_body_gzip VARCHAR NULL, + res_meta_gzip VARCHAR NULL, intent_id VARCHAR NULL, error VARCHAR NULL, probe_token VARCHAR NULL, diff --git a/nlpcraft/src/main/resources/sql/drop_schema.sql b/nlpcraft/src/main/resources/sql/drop_schema.sql index b1ce0b9..f985bae 100644 --- a/nlpcraft/src/main/resources/sql/drop_schema.sql +++ b/nlpcraft/src/main/resources/sql/drop_schema.sql @@ -16,9 +16,7 @@ -- DROP TABLE IF EXISTS proc_log; -DROP TABLE IF EXISTS nc_user_property; DROP TABLE IF EXISTS nc_user; -DROP TABLE IF EXISTS nc_company_property; DROP TABLE IF EXISTS nc_company; DROP TABLE IF EXISTS passwd_pool; DROP TABLE IF EXISTS feedback; \ No newline at end of file diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala index 0248b56..2b3131a 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala @@ -1149,14 +1149,21 @@ object NCUtils extends LazyLogging { * @param rawStr String to compress. * @return Compressed Base64-encoded string. */ + @throws[NCE] def compress(rawStr: String): String = { val arr = new ByteArrayOutputStream(1024) - managed(new GOS(arr)) acquireAndGet { zip ⇒ - zip.write(rawStr.getBytes) - } + try { + managed(new GOS(arr)) acquireAndGet { zip ⇒ + zip.write(rawStr.getBytes) + } - Base64.encodeBase64String(arr.toByteArray) + Base64.encodeBase64String(arr.toByteArray) + } + catch { + // TODO: text. + case e: Exception ⇒ throw new NCE("Error compressing data", e) + } } /** @@ -1165,8 +1172,14 @@ object NCUtils extends LazyLogging { * @param zipStr Compressed string. * @return Uncompressed string. */ + @throws[NCE] def uncompress(zipStr: String): String = - IOUtils.toString(new GIS(new ByteArrayInputStream(Base64.decodeBase64(zipStr))), Charset.defaultCharset()) + try + IOUtils.toString(new GIS(new ByteArrayInputStream(Base64.decodeBase64(zipStr))), Charset.defaultCharset()) + catch { + // TODO: text. + case e: Exception ⇒ throw new NCE("Error decompressing data", e) + } /** * Sleeps number of milliseconds properly handling exceptions. @@ -1672,6 +1685,7 @@ object NCUtils extends LazyLogging { * @param json JSON to convert. * @return */ + @throws[Exception] def jsonToScalaMap(json: String): Map[String, Object] = GSON.fromJson(json, classOf[java.util.HashMap[String, Object]]).asScala.toMap @@ -1681,8 +1695,15 @@ object NCUtils extends LazyLogging { * @param json JSON to convert. * @return */ - def jsonToJavaMap(json: String): java.util.Map[String, Object] = - GSON.fromJson(json, classOf[java.util.HashMap[String, Object]]) + @throws[NCE] + def jsonToJavaMap(json: String): java.util.Map[String, Object] = { + try + GSON.fromJson(json, classOf[java.util.HashMap[String, Object]]) + catch { + // TODO: text + case e: Exception ⇒ throw new NCE(s"Cannot deserialize JSON to map: '$json'", e) + } + } /** * @@ -1690,9 +1711,14 @@ object NCUtils extends LazyLogging { * @param field * @return */ - @throws[Exception] + @throws[NCE] def getJsonBooleanField(json: String, field: String): Boolean = - GSON.getAdapter(classOf[JsonElement]).fromJson(json).getAsJsonObject.get(field).getAsBoolean + try + GSON.getAdapter(classOf[JsonElement]).fromJson(json).getAsJsonObject.get(field).getAsBoolean + catch { + // TODO: text + case e: Exception ⇒ throw new NCE(s"Cannot deserialize JSON to map: '$json'", e) + } /** * diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedResult.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedResult.java index 3ece971..8d20981 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedResult.java +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedResult.java @@ -18,6 +18,8 @@ package org.apache.nlpcraft.model.tools.embedded; import org.apache.nlpcraft.model.*; + +import java.util.Map; import java.util.function.*; /** @@ -68,6 +70,9 @@ public interface NCEmbeddedResult { */ String getBody(); + // TODO: + Map<String, Object> getMeta(); + /** * Gets optional result type. Note that either both result body and type are set or * error message and error code are set, but not both pairs. diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestClientBuilder.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestClientBuilder.java index df39787..550d0a3 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestClientBuilder.java +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestClientBuilder.java @@ -192,6 +192,7 @@ public class NCTestClientBuilder { @SerializedName("usrId") private long userId; @SerializedName("resType") private String resType; @SerializedName("resBody") private Object resBody; + @SerializedName("resMeta") private Object resMeta; @SerializedName("status") private String status; @SerializedName("error") private String error; @SerializedName("createTstamp") private long createTstamp; diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala index 398d1c2..e2d949a 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala @@ -275,6 +275,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { * * @param resType Result type. * @param resBody Result body. + * @param resMeta Result meta. * @param errMsg Error message. * @param errCode Error code. * @param msgName Message name. @@ -284,6 +285,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { def respond( resType: Option[String], resBody: Option[String], + resMeta: Option[JavaMeta], errMsg: Option[String], errCode: Option[Int], msgName: String, @@ -302,6 +304,10 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { if (vOpt.isDefined) msg += name → vOpt.get + def addMeta(name: String, vOpt: Option[JavaMeta]): Unit = + if (vOpt.isDefined) + msg += name → vOpt.get.asInstanceOf[Serializable] + if (resBody.isDefined && resBody.get.length > Config.resultMaxSize) { addOptional("error", Some("Result is too big. Model result must be corrected.")) addOptional("errorCode", Some(RESULT_TOO_BIG)) @@ -311,6 +317,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { addOptional("errorCode", errCode.map(Integer.valueOf)) addOptional("resType", resType) addOptional("resBody", resBody) + addMeta("resMeta", resMeta) addOptional("log", log) addOptional("intentId", intentId) } @@ -322,6 +329,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { override val getOriginalText: String = txt override val getUserId: Long = usrId override val getBody: String = msg.dataOpt[String]("resBody").orNull + override val getMeta: JavaMeta = msg.dataOpt[JavaMeta]("resMeta").orNull override val getType: String = msg.dataOpt[String]("resType").orNull override val getErrorMessage: String = msg.dataOpt[String]("error").orNull override val getErrorCode: Int = msg.dataOpt[Int]("errorCode").getOrElse(0) @@ -394,6 +402,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { respond( None, None, + None, Some(errMsg), Some(errCode), "P2S_ASK_RESULT", @@ -531,6 +540,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { respond( None, None, + None, Some(errMsg), Some(errCode), "P2S_ASK_RESULT", @@ -621,6 +631,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { def respondWithResult(res: NCResult, log: Option[String]): Unit = respond( Some(res.getType), Some(res.getBody), + Some(res.getMetadata), None, None, "P2S_ASK_RESULT", @@ -693,6 +704,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { respond( None, None, + None, Some(e.getMessage), // User provided rejection message. Some(MODEL_REJECTION), "P2S_ASK_RESULT", @@ -722,6 +734,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats { respond( None, None, + None, Some("Processing failed with unexpected error."), // System error message. Some(UNEXPECTED_ERROR), "P2S_ASK_RESULT", diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/impl/NCRequestImpl.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/impl/NCRequestImpl.scala index d828961..394a96e 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/impl/NCRequestImpl.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/impl/NCRequestImpl.scala @@ -17,14 +17,13 @@ package org.apache.nlpcraft.probe.mgrs.nlp.impl -import java.util.{Collections, Optional} import org.apache.nlpcraft.common._ import org.apache.nlpcraft.model._ import org.apache.nlpcraft.model.impl._ -import java.util -import scala.collection._ +import java.util.{Collections, Optional} import scala.collection.JavaConverters._ +import scala.collection._ import scala.compat.java8.OptionConverters._ /** @@ -55,7 +54,7 @@ case class NCRequestImpl(nlpMeta: Map[String, Any], srvReqId: String) extends NC getOpt("COMPANY_CITY"), getOpt("COMPANY_ADDRESS"), getOpt("COMPANY_POSTAL"), - getMap("COMPANY_META") + getOpt("COMPANY_META").orElse(Collections.emptyMap()) ) override lazy val getUser: NCUser = new NCUserImpl( nlpMeta("USER_ID").asInstanceOf[Long], @@ -63,7 +62,7 @@ case class NCRequestImpl(nlpMeta: Map[String, Any], srvReqId: String) extends NC getOpt("LAST_NAME"), getOpt("EMAIL"), getOpt("AVATAR_URL"), - getMap("META"), + getOpt("META").orElse(Collections.emptyMap()), nlpMeta("IS_ADMIN").asInstanceOf[Boolean], nlpMeta("SIGNUP_TSTAMP").asInstanceOf[Long] ) @@ -73,10 +72,4 @@ case class NCRequestImpl(nlpMeta: Map[String, Any], srvReqId: String) extends NC case Some(v) ⇒ Optional.of(v.asInstanceOf[T]) case None ⇒ Optional.empty() } - - private def getMap(key: String): util.Map[String, AnyRef] = { - val m: Optional[JavaMeta] = getOpt(key) - - if (m.isPresent) m.get() else Collections.emptyMap() - } } diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/company/NCCompanyManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/company/NCCompanyManager.scala index 41a6444..0e3937f 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/company/NCCompanyManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/company/NCCompanyManager.scala @@ -21,7 +21,7 @@ import io.opencensus.trace.Span import org.apache.ignite.{IgniteAtomicSequence, IgniteSemaphore} import org.apache.nlpcraft.common.{NCService, _} import org.apache.nlpcraft.server.ignite.NCIgniteInstance -import org.apache.nlpcraft.server.mdo.{NCCompanyMdo, NCCompanyPropertyMdo} +import org.apache.nlpcraft.server.mdo.NCCompanyMdo import org.apache.nlpcraft.server.sql.{NCSql, NCSqlManager} import org.apache.nlpcraft.server.user.NCUserManager @@ -168,7 +168,7 @@ object NCCompanyManager extends NCService with NCIgniteInstance { city: Option[String], address: Option[String], postalCode: Option[String], - props: Option[Map[String, String]], + props: Option[String], parent: Span = null ): Unit = startScopedSpan("updateCompany", parent, "id" → id) { span ⇒ @@ -282,7 +282,7 @@ object NCCompanyManager extends NCService with NCIgniteInstance { adminFirstName: String, adminLastName: String, adminAvatarUrl: Option[String], - props: Option[Map[String, String]], + props: Option[String], mkToken: () ⇒ String, parent: Span = null ): NCCompanyCreationData = { @@ -371,7 +371,7 @@ object NCCompanyManager extends NCService with NCIgniteInstance { adminFirstName: String, adminLastName: String, adminAvatarUrl: Option[String], - props: Option[Map[String, String]], + props: Option[String], parent: Span = null ): NCCompanyCreationData = startScopedSpan("addCompany", parent, "name" → name) { _ ⇒ addCompany0( @@ -391,18 +391,4 @@ object NCCompanyManager extends NCService with NCIgniteInstance { () ⇒ mkToken() ) } - - /** - * Gets company properties for given company ID. - * - * @param id User ID. - * @param parent Optional parent span. - */ - @throws[NCE] - def getCompanyProperties(id: Long, parent: Span = null): Seq[NCCompanyPropertyMdo] = - startScopedSpan("getCompanyProperties", parent, "companyId" → id) { span ⇒ - NCSql.sql { - NCSqlManager.getCompanyProperties(id, span) - } - } } diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyMdo.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyMdo.scala index c4aa5a8..2405bf2 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyMdo.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyMdo.scala @@ -37,6 +37,7 @@ case class NCCompanyMdo( @NCMdoField(column = "postal_code") postalCode: Option[String], @NCMdoField(column = "auth_token") authToken: String, @NCMdoField(column = "auth_token_hash") authTokenHash: String, + @NCMdoField(column = "properties_gzip") propertiesGzip: Option[String], @NCMdoField(column = "created_on") createdOn: Timestamp, @NCMdoField(column = "last_modified_on") lastModifiedOn: Timestamp ) extends NCAnnotatedMdo[NCCompanyMdo] diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyPropertyMdo.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyPropertyMdo.scala deleted file mode 100644 index 695a41c..0000000 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCCompanyPropertyMdo.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.nlpcraft.server.mdo - -import org.apache.nlpcraft.server.mdo.impl._ -import org.apache.nlpcraft.server.sql.NCSql.Implicits.RsParser - -import java.sql.Timestamp - -/** - * Company property MDO. - */ -@NCMdoEntity(table = "nc_company_property") -case class NCCompanyPropertyMdo( - @NCMdoField(column = "id", pk = true) id: Long, - @NCMdoField(column = "company_id") userId: Long, - @NCMdoField(column = "property") property: String, - @NCMdoField(column = "value") value: String, - @NCMdoField(column = "created_on") createdOn: Timestamp, - @NCMdoField(column = "last_modified_on") lastModifiedOn: Timestamp -) extends NCAnnotatedMdo[NCCompanyPropertyMdo] - -object NCCompanyPropertyMdo { - implicit val x: RsParser[NCCompanyPropertyMdo] = - NCAnnotatedMdo.mkRsParser(classOf[NCCompanyPropertyMdo]) -} diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCQueryStateMdo.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCQueryStateMdo.scala index 27f440a..7677b36 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCQueryStateMdo.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCQueryStateMdo.scala @@ -17,8 +17,9 @@ package org.apache.nlpcraft.server.mdo -import java.sql.Timestamp +import org.apache.nlpcraft.common.JavaMeta +import java.sql.Timestamp import org.apache.nlpcraft.server.sql.NCSql.Implicits.RsParser import org.apache.nlpcraft.server.mdo.impl._ @@ -45,6 +46,7 @@ case class NCQueryStateMdo( // Query OK. @NCMdoField var resultType: Option[String] = None, @NCMdoField var resultBody: Option[String] = None, + @NCMdoField var resultMeta: Option[JavaMeta] = None, // Query ERROR. @NCMdoField var error: Option[String] = None, @NCMdoField var errorCode: Option[Int] = None diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserMdo.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserMdo.scala index 9d7be9d..063a4be 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserMdo.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserMdo.scala @@ -36,6 +36,7 @@ case class NCUserMdo( @NCMdoField(column = "last_name") lastName: Option[String], @NCMdoField(column = "avatar_url") avatarUrl: Option[String], @NCMdoField(column = "passwd_salt") passwordSalt: Option[String], + @NCMdoField(column = "properties_gzip") propertiesGzip: Option[String], @NCMdoField(column = "is_admin") isAdmin: Boolean, @NCMdoField(column = "created_on") createdOn: Timestamp, @NCMdoField(column = "last_modified_on") lastModifiedOn: Timestamp @@ -54,11 +55,12 @@ object NCUserMdo { lastName: Option[String], avatarUrl: Option[String], passwordSalt: Option[String], + propertiesGzip: Option[String], isAdmin: Boolean ): NCUserMdo = { val now = U.nowUtcTs() - NCUserMdo(id, companyId, extId, email, firstName, lastName, avatarUrl, passwordSalt, isAdmin, now, now) + NCUserMdo(id, companyId, extId, email, firstName, lastName, avatarUrl, passwordSalt, propertiesGzip, isAdmin, now, now) } def apply( @@ -70,11 +72,12 @@ object NCUserMdo { lastName: Option[String], avatarUrl: Option[String], passwordSalt: Option[String], + propertiesGzip: Option[String], isAdmin: Boolean, createdOn: Timestamp ): NCUserMdo = { require(createdOn != null, "Created date cannot be null.") - NCUserMdo(id, companyId, extId, email, firstName, lastName, avatarUrl, passwordSalt, isAdmin, createdOn, createdOn) + NCUserMdo(id, companyId, extId, email, firstName, lastName, avatarUrl, passwordSalt, propertiesGzip, isAdmin, createdOn, createdOn) } } diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserPropertyMdo.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserPropertyMdo.scala deleted file mode 100644 index f1813cd..0000000 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/mdo/NCUserPropertyMdo.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.nlpcraft.server.mdo - -import java.sql.Timestamp - -import org.apache.nlpcraft.server.mdo.impl._ -import org.apache.nlpcraft.server.sql.NCSql.Implicits.RsParser - -/** - * User property MDO. - */ -@NCMdoEntity(table = "nc_user_property") -case class NCUserPropertyMdo( - @NCMdoField(column = "id", pk = true) id: Long, - @NCMdoField(column = "user_id") userId: Long, - @NCMdoField(column = "property") property: String, - @NCMdoField(column = "value") value: String, - @NCMdoField(column = "created_on") createdOn: Timestamp, - @NCMdoField(column = "last_modified_on") lastModifiedOn: Timestamp -) extends NCAnnotatedMdo[NCUserPropertyMdo] - -object NCUserPropertyMdo { - implicit val x: RsParser[NCUserPropertyMdo] = - NCAnnotatedMdo.mkRsParser(classOf[NCUserPropertyMdo]) -} \ No newline at end of file diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala index 34b654b..9452b83 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala @@ -722,6 +722,7 @@ object NCProbeManager extends NCService { val errCodeOpt = probeMsg.dataOpt[Int]("errorCode") val resTypeOpt = probeMsg.dataOpt[String]("resType") val resBodyOpt = probeMsg.dataOpt[String]("resBody") + val resMetaOpt = probeMsg.dataOpt[JavaMeta]("resMeta") val logJson = probeMsg.dataOpt[String]("log") val intentId = probeMsg.dataOpt[String]("intentId") @@ -740,13 +741,11 @@ object NCProbeManager extends NCService { else { // OK result. require(resTypeOpt.isDefined && resBodyOpt.isDefined, "Result defined") - val resType = resTypeOpt.get - val resBody = resBodyOpt.get - NCQueryManager.setResult( srvReqId, - resType, - resBody, + resTypeOpt.get, + resBodyOpt.get, + resMetaOpt, logJson, intentId ) @@ -849,22 +848,11 @@ object NCProbeManager extends NCService { usrAgent: Option[String], rmtAddr: Option[String], data: Option[String], - usrMeta: Option[Map[String, String]], - companyMeta: Option[Map[String, String]], + usrMeta: Option[JavaMeta], + companyMeta: Option[JavaMeta], enableLog: Boolean, parent: Span = null): Unit = { startScopedSpan("askProbe", parent, "srvReqId" → srvReqId, "usrId" → usr.id, "mdlId" → mdlId, "txt" → txt) { span ⇒ - def convertMeta(metaOpt: Option[Map[String, String]]): util.HashMap[String, String] = - metaOpt match { - case Some(meta) ⇒ - val map = new util.HashMap[String, String]() - - meta.foreach { case (k, v) ⇒ map.put(k, v) } - - map - case None ⇒ null - } - val senMeta = new util.HashMap[String, java.io.Serializable]() Map( @@ -880,7 +868,7 @@ object NCProbeManager extends NCService { "IS_ADMIN" → usr.isAdmin, "AVATAR_URL" → usr.avatarUrl.orNull, "DATA" → data.orNull, - "META" → convertMeta(usrMeta), + "META" → usrMeta.orNull, "COMPANY_ID" → company.id, "COMPANY_NAME" → company.name, "COMPANY_WEBSITE" → company.website.orNull, @@ -889,7 +877,7 @@ object NCProbeManager extends NCService { "COMPANY_CITY" → company.city.orNull, "COMPANY_ADDRESS" → company.address.orNull, "COMPANY_POSTAL" → company.postalCode.orNull, - "COMPANY_META" → convertMeta(companyMeta) + "COMPANY_META" → companyMeta.orNull ). filter(_._2 != null). foreach(p ⇒ senMeta.put(p._1, p._2.asInstanceOf[java.io.Serializable])) diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/proclog/NCProcessLogManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/proclog/NCProcessLogManager.scala index f7958b9..436a0e1 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/proclog/NCProcessLogManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/proclog/NCProcessLogManager.scala @@ -91,6 +91,7 @@ object NCProcessLogManager extends NCService with NCIgniteInstance { * @param errMsg * @param resType * @param resBody + * @param resMeta * @param intentId * @param parent Optional parent span. */ @@ -101,6 +102,7 @@ object NCProcessLogManager extends NCService with NCIgniteInstance { errMsg: Option[String], resType: Option[String], resBody: Option[String], + resMeta: Option[JavaMeta], intentId: Option[String], parent: Span = null ): Unit = @@ -115,6 +117,7 @@ object NCProcessLogManager extends NCService with NCIgniteInstance { errMsg.orNull, resType.orNull, resBody.orNull, + resMeta.orNull, intentId.orNull, tstamp, span diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/query/NCQueryManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/query/NCQueryManager.scala index ad6fdb1..2b762f3 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/query/NCQueryManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/query/NCQueryManager.scala @@ -22,6 +22,7 @@ import org.apache.ignite.IgniteCache import org.apache.ignite.events.{CacheEvent, EventType} import org.apache.nlpcraft.common.ascii.NCAsciiTable import org.apache.nlpcraft.common.pool.NCThreadPoolManager +import org.apache.nlpcraft.common.util.NCUtils.{jsonToJavaMap, uncompress} import org.apache.nlpcraft.common.{NCService, _} import org.apache.nlpcraft.server.apicodes.NCApiStatusCode._ import org.apache.nlpcraft.server.company.NCCompanyManager @@ -221,18 +222,6 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS val usr = NCUserManager.getUserById(usrId, parent).getOrElse(throw new NCE(s"Unknown user ID: $usrId")) val company = NCCompanyManager.getCompany(usr.companyId, parent).getOrElse(throw new NCE(s"Unknown company ID: ${usr.companyId}")) - val usrMeta = { - val m = NCUserManager.getUserProperties(usrId, parent) - - if (m.isEmpty) None else Some(m.map(p ⇒ p.property → p.value).toMap) - } - - val compMeta = { - val m = NCCompanyManager.getCompanyProperties(usr.companyId, parent) - - if (m.isEmpty) None else Some(m.map(p ⇒ p.property → p.value).toMap) - } - // Check input length. if (txt0.split(" ").length > MAX_WORDS) throw new NCE(s"User input is too long (max is $MAX_WORDS words).") @@ -285,6 +274,13 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS val enabledBuiltInToks = NCProbeManager.getModel(mdlId, span).enabledBuiltInTokens + @throws[NCE] + def unzipProperties(gzipOpt: Option[String]): Option[JavaMeta] = + gzipOpt match { + case Some(gzip) ⇒ Some(jsonToJavaMap(uncompress(gzip))) + case None ⇒ None + } + // Enrich the user input and send it to the probe. NCProbeManager.askProbe( srvReqId, @@ -296,8 +292,8 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS usrAgent, rmtAddr, data, - usrMeta, - compMeta, + unzipProperties(usr.propertiesGzip), + unzipProperties(company.propertiesGzip), enableLog, span ) @@ -369,6 +365,7 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS None, None, None, + None, span ) } @@ -379,6 +376,7 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS * @param srvReqId Server request ID. * @param resType * @param resBody + * @param resMeta * @param logJson * @param intentId * @param parent Optional parent span. @@ -388,6 +386,7 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS srvReqId: String, resType: String, resBody: String, + resMeta: Option[JavaMeta], logJson: Option[String], intentId: Option[String], parent: Span = null @@ -407,6 +406,7 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS copy.status = QRY_READY.toString copy.resultType = Some(resType) copy.resultBody = Some(resBody) + copy.resultMeta = resMeta copy.logJson = logJson copy.intentId = intentId @@ -430,6 +430,7 @@ object NCQueryManager extends NCService with NCIgniteInstance with NCOpenCensusS None, resType = Some(resType), resBody = Some(resBody), + resMeta = resMeta, intentId = intentId, span ) diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/rest/NCBasicRestApi.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/rest/NCBasicRestApi.scala index a681a8f..c80c0ac 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/rest/NCBasicRestApi.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/rest/NCBasicRestApi.scala @@ -24,14 +24,17 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers._ import akka.http.scaladsl.server.Directives.{entity, _} import akka.http.scaladsl.server._ -import com.google.gson.Gson +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.typesafe.scalalogging.LazyLogging import io.opencensus.stats.Measure import io.opencensus.trace.{Span, Status} import org.apache.commons.validator.routines.UrlValidator import org.apache.nlpcraft.common.opencensus.NCOpenCensusTrace import org.apache.nlpcraft.common.pool.NCThreadPoolManager -import org.apache.nlpcraft.common.{NCE, U} +import org.apache.nlpcraft.common.util.NCUtils.{jsonToJavaMap, uncompress} +import org.apache.nlpcraft.common.{JavaMeta, NCE, U} import org.apache.nlpcraft.model.NCModelView import org.apache.nlpcraft.server.apicodes.NCApiStatusCode.{API_OK, _} import org.apache.nlpcraft.server.company.NCCompanyManager @@ -52,12 +55,10 @@ import scala.concurrent.{ExecutionContext, Future} * REST API default implementation. */ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace with NCOpenCensusServerStats { - protected final val GSON = new Gson() protected final val URL_VALIDATOR = new UrlValidator(Array("http", "https"), UrlValidator.ALLOW_LOCAL_URLS) final val API_VER = 1 final val API = "api" / s"v$API_VER" - /** */ private final val CORS_HDRS = List( `Access-Control-Allow-Origin`.*, @@ -65,6 +66,10 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w `Access-Control-Allow-Headers`("Authorization", "Content-Type", "X-Requested-With") ) + private final val JS_MAPPER = new ObjectMapper() + + JS_MAPPER.registerModule(DefaultScalaModule) + /* * General control exception. * Note that these classes must be public because scala 2.11 internal errors (compilations problems). @@ -132,6 +137,21 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w /** * + * @param o + * @throws + * @return + */ + @throws[NCE] + private def toJs(o: AnyRef): String = + try + JS_MAPPER.writeValueAsString(o) + catch { + // TODO: text + case e: JsonProcessingException ⇒ throw new NCE("Serialization error", e) + } + + /** + * * @param acsTkn Access token to check. * @param shouldBeAdmin Admin flag. * @return @@ -220,28 +240,38 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w else s.resultBody.orNull ), + "resMeta" → s.resultMeta.orNull, "error" → s.error.orNull, "errorCode" → s.errorCode.map(Integer.valueOf).orNull, "logHolder" → (if (s.logJson.isDefined) U.jsonToObject(s.logJson.get) else null), "intentId" → s.intentId.orNull ).filter(_._2 != null).asJava + /** - * Checks properties. + * Extracts and checks JSON. * - * @param propsOpt Optional properties. + * @param jsOpt JSON value. Optional. + * @param name Property name. */ @throws[TooLargeField] - private def checkProperties(propsOpt: Option[Map[String, String]]): Unit = - propsOpt match { - case Some(props) ⇒ - props.foreach { case (k, v) ⇒ - checkLength(k, k, 64) - - if (v != null && v.nonEmpty && v.length > 512) - throw TooLargeField(v, 512) + @throws[InvalidField] + private def extractJson(jsOpt: Option[spray.json.JsValue], name: String): Option[String] = + jsOpt match { + case Some(js) ⇒ + val s = js.compactPrint + + checkLength(name, s, 512000) + + // Validates. + try + U.jsonToJavaMap(s) + catch { + case _: NCE ⇒ throw InvalidField(name) } - case None ⇒ // No-op. + + Some(s) + case None ⇒ None } /** @@ -526,9 +556,28 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w * * @param fut */ - private def successWithJs(fut: Future[String]): Route = onSuccess(fut) { - js ⇒ complete(HttpResponse(entity = HttpEntity(ContentTypes.`application/json`, js))) - } + private def successWithJs(fut: Future[String]): Route = + onSuccess(fut) { + js ⇒ complete(HttpResponse(entity = HttpEntity(ContentTypes.`application/json`, js))) + } + + /** + * + * @param o + */ + private def completeJs(o: Object): Route = + complete(HttpResponse(entity = HttpEntity(ContentTypes.`application/json`, toJs(o)))) + + /** + * + * @param gzipOpt + */ + @throws[NCE] + private def unzipProperties(gzipOpt: Option[String]): Option[JavaMeta] = + gzipOpt match { + case Some(gzip) ⇒ Some(jsonToJavaMap(uncompress(gzip))) + case None ⇒ None + } /** * @@ -559,14 +608,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w "acsTok" → req.acsTok, "usrExtId" → req.usrExtId, "mdlId" → req.mdlId, "txt" → req.txt ) - val dataJsOpt = - req.data match { - case Some(data) ⇒ Some(data.compactPrint) - case None ⇒ None - } - - checkLengthOpt("data", dataJsOpt,512000) - + val dataJs = extractJson(req.data, "data") val acsUsr = authenticate(req.acsTok) checkModelId(req.mdlId, acsUsr.companyId) @@ -579,7 +621,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w mdlId = req.mdlId, usrAgent = usrAgent, rmtAddr = getAddress(rmtAddr), - data = dataJsOpt, + data = dataJs, req.enableLog.getOrElse(false), parent = span )) @@ -640,8 +682,8 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w successWithJs( fut.collect { - // We have to use GSON (not spray) here to serialize 'resBody' field. - case res ⇒ GSON.toJson( + // We have to use Jackson (not spray) here to serialize 'resBody' field. + case res ⇒ toJs( Map( "status" → API_OK.toString, "state" → queryStateToMap(res) @@ -724,8 +766,8 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w toSeq.sortBy(-_.createTstamp.getTime). take(req.maxRows.getOrElse(Integer.MAX_VALUE)) - // We have to use GSON (not spray) here to serialize 'resBody' field. - val js = GSON.toJson( + // We have to use Jackson (not spray) here to serialize 'resBody' field. + val js = toJs( Map( "status" → API_OK.toString, "states" → states.map(queryStateToMap).asJava @@ -772,8 +814,8 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w successWithJs( fut.collect { - // We have to use GSON (not spray) here to serialize 'result' field. - case res ⇒ GSON.toJson(Map("status" → API_OK.toString, "result" → res).asJava) + // We have to use Jackson (not spray) here to serialize 'result' field. + case res ⇒ toJs(Map("status" → API_OK.toString, "result" → res).asJava) } ) } @@ -881,7 +923,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w adminFirstName: String, adminLastName: String, adminAvatarUrl: Option[String], - properties: Option[Map[String, String]] + properties: Option[spray.json.JsValue] ) case class Res$Company$Add( status: String, @@ -911,7 +953,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w "adminAvatarUrl" → req.adminAvatarUrl ) - checkProperties(req.properties) + val propsJs = extractJson(req.properties, "properties") // Via REST only administrators of already created companies can create new companies. authenticateAsAdmin(req.acsTok) @@ -929,7 +971,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w req.adminFirstName, req.adminLastName, req.adminAvatarUrl, - req.properties, + propsJs, span ) @@ -958,11 +1000,10 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w city: Option[String], address: Option[String], postalCode: Option[String], - properties: Option[Map[String, String]] + properties: Option[JavaMeta] ) implicit val reqFmt: RootJsonFormat[Req$Company$Get] = jsonFormat1(Req$Company$Get) - implicit val resFmt: RootJsonFormat[Res$Company$Get] = jsonFormat10(Res$Company$Get) entity(as[Req$Company$Get]) { req ⇒ startScopedSpan("company$get", "acsTok" → req.acsTok) { span ⇒ @@ -974,9 +1015,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w getCompany(acsUsr.companyId, span). getOrElse(throw new NCE(s"Company not found: ${acsUsr.companyId}")) - val props = NCCompanyManager.getCompanyProperties(acsUsr.companyId, span) - - complete { + completeJs { Res$Company$Get(API_OK, company.id, company.name, @@ -986,7 +1025,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w company.city, company.address, company.postalCode, - if (props.isEmpty) None else Some(props.map(p ⇒ p.property → p.value).toMap) + unzipProperties(company.propertiesGzip) ) } } @@ -1010,7 +1049,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w city: Option[String], address: Option[String], postalCode: Option[String], - properties: Option[Map[String, String]] + properties: Option[spray.json.JsValue] ) case class Res$Company$Update( status: String @@ -1031,8 +1070,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w "postalCode" → req.postalCode ) - checkProperties(req.properties) - + val propsJs = extractJson(req.properties, "properties") val admUsr = authenticateAsAdmin(req.acsTok) NCCompanyManager.updateCompany( @@ -1044,7 +1082,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w req.city, req.address, req.postalCode, - req.properties, + propsJs, span ) @@ -1314,7 +1352,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w lastName: String, avatarUrl: Option[String], isAdmin: Boolean, - properties: Option[Map[String, String]], + properties: Option[spray.json.JsValue], usrExtId: Option[String] ) case class Res$User$Add( @@ -1337,8 +1375,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w "usrExtId" → req.usrExtId ) - checkProperties(req.properties) - + val propsJs = extractJson(req.properties, "properties") val admUsr = authenticateAsAdmin(req.acsTok) val id = NCUserManager.addUser( @@ -1349,7 +1386,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w req.lastName, req.avatarUrl, req.isAdmin, - req.properties, + propsJs, req.usrExtId, span ) @@ -1375,7 +1412,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w firstName: String, lastName: String, avatarUrl: Option[String], - properties: Option[Map[String, String]] + properties: Option[spray.json.JsValue] ) case class Res$User$Update( status: String @@ -1393,8 +1430,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w "avatarUrl" → req.avatarUrl ) - checkProperties(req.properties) - + val propsJs = extractJson(req.properties, "properties") val acsUsr = authenticate(req.acsTok) NCUserManager.updateUser( @@ -1402,7 +1438,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w req.firstName, req.lastName, req.avatarUrl, - req.properties, + propsJs, span ) @@ -1454,7 +1490,6 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w NCUserManager. getAllUsers(acsUsr.companyId, span). - keys. filter(_.id != acsUsr.id). map(_.id). foreach(delete) @@ -1575,7 +1610,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w avatarUrl: Option[String], isAdmin: Boolean, companyId: Long, - properties: Option[Map[String, String]] + properties: Option[JavaMeta] ) case class Res$User$All( status: String, @@ -1583,8 +1618,6 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w ) implicit val reqFmt: RootJsonFormat[Req$User$All] = jsonFormat1(Req$User$All) - implicit val usrFmt: RootJsonFormat[ResUser_User$All] = jsonFormat9(ResUser_User$All) - implicit val resFmt: RootJsonFormat[Res$User$All] = jsonFormat2(Res$User$All) entity(as[Req$User$All]) { req ⇒ startScopedSpan("user$All", "acsTok" → req.acsTok) { span ⇒ @@ -1592,23 +1625,23 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w val admUSr = authenticateAsAdmin(req.acsTok) - val usrLst = - NCUserManager.getAllUsers(admUSr.companyId, span).map { case (u, props) ⇒ - ResUser_User$All( - u.id, - u.email, - u.extId, - u.firstName, - u.lastName, - u.avatarUrl, - u.isAdmin, - u.companyId, - if (props.isEmpty) None else Some(props.map(p ⇒ p.property → p.value).toMap) + completeJs { + Res$User$All( + API_OK, + NCUserManager.getAllUsers(admUSr.companyId, span).map(u ⇒ + ResUser_User$All( + u.id, + u.email, + u.extId, + u.firstName, + u.lastName, + u.avatarUrl, + u.isAdmin, + u.companyId, + unzipProperties(u.propertiesGzip) + ) ) - }.toSeq - - complete { - Res$User$All(API_OK, usrLst) + ) } } } @@ -1634,11 +1667,10 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w lastName: Option[String], avatarUrl: Option[String], isAdmin: Boolean, - properties: Option[Map[String, String]] + properties: Option[JavaMeta] ) implicit val reqFmt: RootJsonFormat[Req$User$Get] = jsonFormat3(Req$User$Get) - implicit val resFmt: RootJsonFormat[Res$User$Get] = jsonFormat9(Res$User$Get) entity(as[Req$User$Get]) { req ⇒ startScopedSpan( @@ -1653,9 +1685,8 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w throw AdminRequired(acsUsr.email.get) val usr = NCUserManager.getUserById(usrId, span).getOrElse(throw new NCE(s"User not found: $usrId")) - val props = NCUserManager.getUserProperties(usrId, span) - complete { + completeJs { Res$User$Get(API_OK, usr.id, usr.email, @@ -1664,7 +1695,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w usr.lastName, usr.avatarUrl, usr.isAdmin, - if (props.isEmpty) None else Some(props.map(p ⇒ p.property → p.value).toMap) + unzipProperties(usr.propertiesGzip) ) } } @@ -1771,7 +1802,7 @@ class NCBasicRestApi extends NCRestApi with LazyLogging with NCOpenCensusTrace w status = statusCode, entity = HttpEntity( ContentTypes.`application/json`, - GSON.toJson(Map("code" → errCode, "msg" → errMsg).asJava) + toJs(Map("code" → errCode, "msg" → errMsg).asJava) ) ) ) diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/sql/NCSqlManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/sql/NCSqlManager.scala index 00fe81b..3ef2551 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/sql/NCSqlManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/sql/NCSqlManager.scala @@ -17,8 +17,10 @@ package org.apache.nlpcraft.server.sql +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.scala.DefaultScalaModule import io.opencensus.trace.Span -import org.apache.ignite.IgniteAtomicSequence import org.apache.nlpcraft.common.config.NCConfigurable import org.apache.nlpcraft.common.{NCService, _} import org.apache.nlpcraft.server.apicodes.NCApiStatusCode._ @@ -27,7 +29,6 @@ import org.apache.nlpcraft.server.mdo._ import org.apache.nlpcraft.server.sql.NCSql.Implicits._ import java.sql.Timestamp -import scala.util.control.Exception.catching /** * Provides basic CRUD and often used operations on RDBMS. @@ -35,7 +36,7 @@ import scala.util.control.Exception.catching */ object NCSqlManager extends NCService with NCIgniteInstance { private final val DB_TABLES = Seq( - "nc_company", "nc_company_property", "nc_user", "nc_user_property", "passwd_pool", "proc_log", "feedback" + "nc_company", "nc_user", "passwd_pool", "proc_log", "feedback" ) private final val CACHE_2_CLEAR = Seq( "user-token-signin-cache", @@ -45,13 +46,46 @@ object NCSqlManager extends NCService with NCIgniteInstance { "stanford-cache", "opennlp-cache" ) - + + private final val JS_MAPPER = new ObjectMapper() + + JS_MAPPER.registerModule(DefaultScalaModule) + private object Config extends NCConfigurable { def init: Boolean = getBoolOpt("nlpcraft.server.database.igniteDbInitialize").getOrElse(false) } - @volatile private var usersPropsSeq: IgniteAtomicSequence = _ - @volatile private var compPropsSeq: IgniteAtomicSequence = _ + /** + * + * @param opt + */ + @throws[NCE] + private def gzip(opt: Option[String]): String = + opt match { + case Some(s) ⇒ U.compress(s) + case None ⇒ null + } + + /** + * + * @param nullable + */ + @throws[NCE] + private def gzip(nullable: String): String = if (nullable != null) U.compress(nullable) else null + + /** + * + * @param m + */ + @throws[NCE] + private def gzip(m: JavaMeta): String = { + try + if (m != null) U.compress(JS_MAPPER.writeValueAsString(m)) else null + catch { + // TODO: text + case e: JsonProcessingException ⇒ throw new NCE("Serialization error", e) + } + } /** * @@ -68,11 +102,6 @@ object NCSqlManager extends NCService with NCIgniteInstance { if (NCSql.isIgniteDb) prepareIgniteSchema() - catching(wrapIE) { - usersPropsSeq = NCSql.mkSeq(ignite, "usersPropsSeq", "nc_user_property", "id") - compPropsSeq = NCSql.mkSeq(ignite, "companiesPropsSeq", "nc_company_property", "id") - } - ackStarted() } @@ -163,7 +192,6 @@ object NCSqlManager extends NCService with NCIgniteInstance { @throws[NCE] def deleteUser(id: Long, parent: Span): Int = startScopedSpan("deleteUser", parent, "usrId" → id) { _ ⇒ - NCSql.delete("DELETE FROM nc_user_property WHERE user_id = ?", id) NCSql.delete("DELETE FROM nc_user WHERE id = ?", id) } @@ -176,7 +204,6 @@ object NCSqlManager extends NCService with NCIgniteInstance { @throws[NCE] def deleteCompany(id: Long, parent: Span): Int = startScopedSpan("deleteCompany", parent, "compId" → id) { _ ⇒ - NCSql.delete("DELETE FROM nc_user_property WHERE user_id IN (SELECT id FROM nc_user WHERE company_id = ?)", id) NCSql.delete("DELETE FROM nc_user WHERE company_id = ?", id) NCSql.delete("DELETE FROM nc_company WHERE id = ?", id) } @@ -197,33 +224,28 @@ object NCSqlManager extends NCService with NCIgniteInstance { firstName: String, lastName: String, avatarUrl: Option[String], - propsOpt: Option[Map[String, String]], + propsOpt: Option[String], parent: Span ): Int = - startScopedSpan("updateUser", parent, "usrId" → id) { span ⇒ - val n = - NCSql.update( - s""" - |UPDATE nc_user - |SET - | first_name = ?, - | last_name = ?, - | avatar_url = ?, - | last_modified_on = ? - |WHERE id = ? - """.stripMargin, - firstName, - lastName, - avatarUrl.orNull, - U.nowUtcTs(), - id - ) - - NCSql.delete("DELETE FROM nc_user_property WHERE user_id = ?", id) - - addUserProperties(id, propsOpt, span) - - n + startScopedSpan("updateUser", parent, "usrId" → id) { _ ⇒ + NCSql.update( + s""" + |UPDATE nc_user + |SET + | first_name = ?, + | last_name = ?, + | avatar_url = ?, + | properties_gzip = ?, + | last_modified_on = ? + |WHERE id = ? + """.stripMargin, + firstName, + lastName, + avatarUrl.orNull, + gzip(propsOpt), + U.nowUtcTs(), + id + ) } /** @@ -246,97 +268,32 @@ object NCSqlManager extends NCService with NCIgniteInstance { firstName: String, lastName: String, avatarUrl: Option[String], - propsOpt: Option[Map[String, String]], + propsOpt: Option[String], parent: Span ): Int = startScopedSpan("updateUser", parent, "usrId" → id) { span ⇒ - val n = - NCSql.update( - s""" - |UPDATE nc_user - |SET - | email = ?, - | passwd_salt = ?, - | first_name = ?, - | last_name = ?, - | avatar_url = ?, - | last_modified_on = ? - |WHERE id = ? - """.stripMargin, - email, - passwdSalt, - firstName, - lastName, - avatarUrl.orNull, - U.nowUtcTs(), - id - ) - - NCSql.delete("DELETE FROM nc_user_property WHERE user_id = ?", id) - - addUserProperties(id, propsOpt, span) - - n - } - - /** - * - * @param id - * @param propsOpt - * @param parent Optional parent span. - */ - private def addUserProperties(id: Long, propsOpt: Option[Map[String, String]], parent: Span): Unit = - startScopedSpan("addUserProperties", parent, "usrId" → id) { _ ⇒ - propsOpt match { - case Some(props) ⇒ - val now = U.nowUtcTs() - - props.foreach { case (k, v) ⇒ - NCSql.insert( - s""" - |INSERT INTO nc_user_property (id, user_id, property, value, created_on, last_modified_on) - |VALUES(?, ?, ?, ?, ?, ?) - """.stripMargin, - usersPropsSeq.getAndIncrement(), - id, - k, - v, - now, - now - ) - } - case None ⇒ // No-op. - } - } - - /** - * - * @param id - * @param propsOpt - * @param parent Optional parent span. - */ - private def addCompanyProperties(id: Long, propsOpt: Option[Map[String, String]], parent: Span): Unit = - startScopedSpan("addCompanyProperties", parent, "companyId" → id) { _ ⇒ - propsOpt match { - case Some(props) ⇒ - val now = U.nowUtcTs() - - props.foreach { case (k, v) ⇒ - NCSql.insert( - s""" - |INSERT INTO nc_company_property (id, company_id, property, value, created_on, last_modified_on) - |VALUES(?, ?, ?, ?, ?, ?) - """.stripMargin, - compPropsSeq.getAndIncrement(), - id, - k, - v, - now, - now - ) - } - case None ⇒ // No-op. - } + NCSql.update( + s""" + |UPDATE nc_user + |SET + | email = ?, + | passwd_salt = ?, + | first_name = ?, + | last_name = ?, + | avatar_url = ?, + | properties_gzip = ?, + | last_modified_on = ? + |WHERE id = ? + """.stripMargin, + email, + passwdSalt, + firstName, + lastName, + avatarUrl.orNull, + gzip(propsOpt), + U.nowUtcTs(), + id + ) } /** @@ -387,11 +344,11 @@ object NCSqlManager extends NCService with NCIgniteInstance { city: Option[String], address: Option[String], postalCode: Option[String], - propsOpt: Option[Map[String, String]], + propsOpt: Option[String], parent: Span ): Int = startScopedSpan("updateCompany", parent, "compId" → id) { _ ⇒ - val res = NCSql.update( + NCSql.update( s""" |UPDATE nc_company |SET @@ -402,6 +359,7 @@ object NCSqlManager extends NCService with NCIgniteInstance { | city = ?, | address = ?, | postal_code = ?, + | properties_gzip = ?, | last_modified_on = ? |WHERE id = ? """.stripMargin, @@ -412,15 +370,10 @@ object NCSqlManager extends NCService with NCIgniteInstance { city.orNull, address.orNull, postalCode.orNull, + gzip(propsOpt), U.nowUtcTs(), id ) - - NCSql.delete("DELETE FROM nc_company_property WHERE company_id = ?", id) - - addCompanyProperties(id, propsOpt, parent) - - res } /** @@ -530,34 +483,6 @@ object NCSqlManager extends NCService with NCIgniteInstance { } /** - * Gets user properties for given ID. - * - * @param id User ID. - * @param parent Optional parent span. - * @return User properties. - * - */ - @throws[NCE] - def getUserProperties(id: Long, parent: Span): Seq[NCUserPropertyMdo] = - startScopedSpan("getUserProperties", parent, "usrId" → id) { _ ⇒ - NCSql.select[NCUserPropertyMdo]("SELECT * FROM nc_user_property WHERE user_id = ?", id) - } - - /** - * Gets company properties for given ID. - * - * @param id User ID. - * @param parent Optional parent span. - * @return Company properties. - * - */ - @throws[NCE] - def getCompanyProperties(id: Long, parent: Span): Seq[NCCompanyPropertyMdo] = - startScopedSpan("getCompanyProperties", parent, "usrId" → id) { _ ⇒ - NCSql.select[NCCompanyPropertyMdo]("SELECT * FROM nc_company_property WHERE company_id = ?", id) - } - - /** * Gets user properties for given external ID. * * @param companyId Company ID. @@ -593,15 +518,9 @@ object NCSqlManager extends NCService with NCIgniteInstance { * @param parent Optional parent span. */ @throws[NCE] - def getAllUsers(compId: Long, parent: Span): Map[NCUserMdo, Seq[NCUserPropertyMdo]] = + def getAllUsers(compId: Long, parent: Span): Seq[NCUserMdo] = startScopedSpan("getAllUsers", parent, "compId" → compId) { _ ⇒ - val props = NCSql.select[NCUserPropertyMdo]( - "SELECT * FROM nc_user_property WHERE user_id IN (SELECT id FROM nc_user WHERE company_id = ?)", - compId - ).groupBy(_.userId) - - NCSql.select[NCUserMdo]("SELECT * FROM nc_user WHERE company_id = ?", compId). - map(p ⇒ p → props.getOrElse(p.id, Nil)).toMap + NCSql.select[NCUserMdo]("SELECT * FROM nc_user WHERE company_id = ?", compId) } /** @@ -643,7 +562,7 @@ object NCSqlManager extends NCService with NCIgniteInstance { city: Option[String], address: Option[String], postalCode: Option[String], - propsOpt: Option[Map[String, String]], + propsOpt: Option[String], parent: Span ): Unit = startScopedSpan("addCompany", parent, "compId" → id, "name" → name, "tkn" → tkn) { _ ⇒ @@ -663,10 +582,11 @@ object NCSqlManager extends NCService with NCIgniteInstance { | postal_code, | auth_token, | auth_token_hash, + | properties_gzip, | created_on, | last_modified_on |) - | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """.stripMargin, id, name, @@ -678,11 +598,10 @@ object NCSqlManager extends NCService with NCIgniteInstance { postalCode.orNull, tkn, U.mkSha256Hash(tkn), + gzip(propsOpt), now, now ) - - addCompanyProperties(id, propsOpt, parent) } /** @@ -711,7 +630,7 @@ object NCSqlManager extends NCService with NCIgniteInstance { avatarUrl: Option[String], passwdSalt: Option[String], isAdmin: Boolean, - propsOpt: Option[Map[String, String]], + propsOpt: Option[String], parent: Span ): Unit = { require(usrExtId.isDefined ^ email.isDefined) @@ -739,11 +658,12 @@ object NCSqlManager extends NCService with NCIgniteInstance { | email, | passwd_salt, | avatar_url, + | properties_gzip, | is_admin, | created_on, | last_modified_on | ) - | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """.stripMargin, id, compId, @@ -753,12 +673,11 @@ object NCSqlManager extends NCService with NCIgniteInstance { email.orNull, passwdSalt.orNull, avatarUrl.orNull, + gzip(propsOpt), isAdmin, now, now ) - - addUserProperties(id, propsOpt, span) } } @@ -852,6 +771,7 @@ object NCSqlManager extends NCService with NCIgniteInstance { * @param errMsg * @param resType * @param resBody + * @param resMeta * @param intentId * @param tstamp * @param parent Optional parent span. @@ -862,9 +782,11 @@ object NCSqlManager extends NCService with NCIgniteInstance { errMsg: String, resType: String, resBody: String, + resMeta: JavaMeta, intentId: String, tstamp: Timestamp, - parent: Span): Unit = + parent: Span + ): Unit = startScopedSpan("updateReadyProcessingLog", parent, "srvReqId" → srvReqId) { _ ⇒ NCSql.update( """ @@ -874,6 +796,7 @@ object NCSqlManager extends NCService with NCIgniteInstance { | error = ?, | res_type = ?, | res_body_gzip = ?, + | res_meta_gzip = ?, | intent_id = ?, | resp_tstamp = ? |WHERE srv_req_id = ? @@ -881,7 +804,8 @@ object NCSqlManager extends NCService with NCIgniteInstance { QRY_READY.toString, errMsg, resType, - if (resBody == null) null else U.compress(resBody), + gzip(resBody), + gzip(resMeta), intentId, tstamp, srvReqId diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/user/NCUserManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/user/NCUserManager.scala index 4471b31..7107085 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/user/NCUserManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/user/NCUserManager.scala @@ -27,7 +27,7 @@ import org.apache.nlpcraft.common.config.NCConfigurable import org.apache.nlpcraft.common.{NCService, _} import org.apache.nlpcraft.server.ignite.NCIgniteHelpers._ import org.apache.nlpcraft.server.ignite.NCIgniteInstance -import org.apache.nlpcraft.server.mdo.{NCUserMdo, NCUserPropertyMdo} +import org.apache.nlpcraft.server.mdo.NCUserMdo import org.apache.nlpcraft.server.sql.{NCSql, NCSqlManager} import org.apache.nlpcraft.server.tx.NCTxManager @@ -190,7 +190,7 @@ object NCUserManager extends NCService with NCIgniteInstance { * @param parent Optional parent span. */ @throws[NCE] - def getAllUsers(compId: Long, parent: Span = null): Map[NCUserMdo, Seq[NCUserPropertyMdo]] = + def getAllUsers(compId: Long, parent: Span = null): Seq[NCUserMdo] = NCSql.sql { NCSqlManager.getAllUsers(compId, parent) } @@ -313,20 +313,6 @@ object NCUserManager extends NCService with NCIgniteInstance { } /** - * Gets user properties for given user ID. - * - * @param id User ID. - * @param parent Optional parent span. - */ - @throws[NCE] - def getUserProperties(id: Long, parent: Span = null): Seq[NCUserPropertyMdo] = - startScopedSpan("getUserProperties", parent, "usrId" → id) { span ⇒ - NCSql.sql { - NCSqlManager.getUserProperties(id, span) - } - } - - /** * * @param email User email (as username). * @param passwd User password. @@ -391,7 +377,7 @@ object NCUserManager extends NCService with NCIgniteInstance { firstName: String, lastName: String, avatarUrl: Option[String], - props: Option[Map[String, String]], + props: Option[String], parent: Span = null ): Unit = startScopedSpan("updateUser", parent, "usrId" → id) { span ⇒ @@ -488,7 +474,7 @@ object NCUserManager extends NCService with NCIgniteInstance { lastName: String, avatarUrl: Option[String], isAdmin: Boolean, - props: Option[Map[String, String]], + props: Option[String], usrExtIdOpt: Option[String], parent: Span = null ): Long = diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/server/rest/NCRestSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/server/rest/NCRestSpec.scala index 98bc498..098b582 100644 --- a/nlpcraft/src/test/scala/org/apache/nlpcraft/server/rest/NCRestSpec.scala +++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/server/rest/NCRestSpec.scala @@ -48,6 +48,9 @@ object NCRestSpec { val code = resp.getStatusLine.getStatusCode val js = mkJs(code, resp.getEntity) + if (js == null) + throw new RuntimeException(s"Unexpected response [code=$code, response=$js]") + code match { case 200 ⇒ GSON.fromJson(js, TYPE_RESP) diff --git a/openapi/nlpcraft_swagger.yml b/openapi/nlpcraft_swagger.yml index f8b0114..fbf0f1c 100644 --- a/openapi/nlpcraft_swagger.yml +++ b/openapi/nlpcraft_swagger.yml @@ -871,7 +871,7 @@ paths: maxLength: 512000 properties: type: object - description: <em>Optional.</em> Additional user properties. + description: <em>Optional.</em> Additional user properties with maximum JSON length of 512000 bytes. additionalProperties: type: string responses: @@ -1064,7 +1064,7 @@ paths: description: Admin flag. properties: type: object - description: <em>Optional.</em> Additional user properties. + description: <em>Optional.</em> Additional user properties with maximum JSON length of 512000 bytes. additionalProperties: type: string usrExtId: @@ -1240,7 +1240,7 @@ paths: maxLength: 512000 properties: type: object - description: <em>Optional.</em> Additional company properties. + description: <em>Optional.</em> Additional company properties with maximum JSON length of 512000 bytes. additionalProperties: type: string responses: @@ -1323,7 +1323,7 @@ paths: maxLength: 512 properties: type: object - description: <em>Optional.</em> Additional company properties. + description: <em>Optional.</em> Additional company properties with maximum JSON length of 512000 bytes. additionalProperties: type: string responses: diff --git a/sql/mysql/drop_schema.sql b/sql/mysql/drop_schema.sql index fba01aa..e1ead27 100644 --- a/sql/mysql/drop_schema.sql +++ b/sql/mysql/drop_schema.sql @@ -18,9 +18,7 @@ USE nlpcraft; DROP TABLE IF EXISTS proc_log; -DROP TABLE IF EXISTS nc_user_property; DROP TABLE IF EXISTS nc_user; -DROP TABLE IF EXISTS nc_company_property; DROP TABLE IF EXISTS nc_company; DROP TABLE IF EXISTS passwd_pool; DROP TABLE IF EXISTS feedback; diff --git a/sql/mysql/schema.sql b/sql/mysql/schema.sql index cac0bf8..9022ab6 100644 --- a/sql/mysql/schema.sql +++ b/sql/mysql/schema.sql @@ -39,6 +39,7 @@ CREATE TABLE nc_company ( postal_code VARCHAR(32), auth_token VARCHAR(64) NOT NULL, auth_token_hash VARCHAR(64) NOT NULL, + properties_gzip TEXT NULL, created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3) ); @@ -48,19 +49,6 @@ CREATE UNIQUE INDEX nc_company_idx_2 ON nc_company(auth_token); CREATE UNIQUE INDEX nc_company_idx_3 ON nc_company(auth_token_hash); -- --- Company properties table. --- -CREATE TABLE nc_company_property ( - id SERIAL PRIMARY KEY, - company_id BIGINT UNSIGNED NOT NULL, - property VARCHAR(64) NOT NULL, - value VARCHAR(512) NULL, - created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - FOREIGN KEY (company_id) REFERENCES nc_company(id) -); - --- -- User table. -- CREATE TABLE nc_user ( @@ -73,6 +61,7 @@ CREATE TABLE nc_user ( last_name VARCHAR(64) NULL, is_admin BOOLEAN NOT NULL, -- Whether or not created with admin token. passwd_salt VARCHAR(64) NULL, + properties_gzip TEXT NULL, created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), FOREIGN KEY (company_id) REFERENCES nc_company(id) @@ -82,19 +71,6 @@ CREATE UNIQUE INDEX nc_user_idx_1 ON nc_user(email); CREATE UNIQUE INDEX nc_user_idx_2 ON nc_user(company_id, ext_id); -- --- User properties table. --- -CREATE TABLE nc_user_property ( - id SERIAL PRIMARY KEY, - user_id BIGINT UNSIGNED NOT NULL, - property VARCHAR(64) NOT NULL, - value VARCHAR(512) NULL, - created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - FOREIGN KEY (user_id) REFERENCES nc_user(id) -); - --- -- Pool of password hashes. -- CREATE TABLE passwd_pool ( @@ -122,6 +98,7 @@ CREATE TABLE proc_log ( -- Result parts. res_type VARCHAR(32) NULL, res_body_gzip TEXT NULL, -- GZIP-ed result body. + res_body_meta TEXT NULL, -- GZIP-ed result meta. intent_id VARCHAR(256) NULL, error TEXT NULL, -- Probe information for this request. diff --git a/sql/oracle/drop_schema.sql b/sql/oracle/drop_schema.sql index 652bdb8..78bd027 100644 --- a/sql/oracle/drop_schema.sql +++ b/sql/oracle/drop_schema.sql @@ -24,14 +24,6 @@ EXCEPTION WHEN OTHERS THEN END; BEGIN - EXECUTE IMMEDIATE 'DROP TABLE nc_user_property'; -EXCEPTION WHEN OTHERS THEN - IF SQLCODE != -942 THEN - RAISE; - END IF; -END; - -BEGIN EXECUTE IMMEDIATE 'DROP TABLE nc_user'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN @@ -40,14 +32,6 @@ EXCEPTION WHEN OTHERS THEN END; BEGIN - EXECUTE IMMEDIATE 'DROP TABLE nc_company_property'; -EXCEPTION WHEN OTHERS THEN - IF SQLCODE != -942 THEN - RAISE; -END IF; -END; - -BEGIN EXECUTE IMMEDIATE 'DROP TABLE nc_company'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN diff --git a/sql/oracle/schema.sql b/sql/oracle/schema.sql index 1ad495c..da243b9 100644 --- a/sql/oracle/schema.sql +++ b/sql/oracle/schema.sql @@ -37,6 +37,7 @@ CREATE TABLE nc_company ( postal_code VARCHAR2(32), auth_token VARCHAR2(64) NOT NULL, auth_token_hash VARCHAR2(64) NOT NULL, + properties_gzip CLOB NULL, created_on DATE DEFAULT sysdate NOT NULL, last_modified_on DATE DEFAULT sysdate NOT NULL ); @@ -46,21 +47,6 @@ CREATE UNIQUE INDEX nc_company_idx_2 ON nc_company(auth_token); CREATE UNIQUE INDEX nc_company_idx_3 ON nc_company(auth_token_hash); -- --- Company properties table. --- -CREATE TABLE nc_company_property ( - id NUMBER PRIMARY KEY, - company_id NUMBER NOT NULL, - property VARCHAR2(64) NOT NULL, - value VARCHAR2(512) NULL, - created_on DATE DEFAULT sysdate NOT NULL, - last_modified_on DATE DEFAULT sysdate NOT NULL, - CONSTRAINT fk_company_id_company_property FOREIGN KEY (company_id) REFERENCES nc_company(id) -); - -CREATE INDEX nc_company_property_idx1 ON nc_company_property(company_id); - --- -- User table. -- CREATE TABLE nc_user ( @@ -73,6 +59,7 @@ CREATE TABLE nc_user ( last_name VARCHAR2(64) NULL, is_admin NUMBER(1) NOT NULL, -- Whether or not created with admin token. passwd_salt VARCHAR2(64) NULL, + properties_gzip CLOB NULL, created_on DATE DEFAULT sysdate NOT NULL, last_modified_on DATE DEFAULT sysdate NOT NULL, CONSTRAINT fk_company_id_user FOREIGN KEY (company_id) REFERENCES nc_company(id) @@ -83,21 +70,6 @@ CREATE UNIQUE INDEX nc_user_idx_2 ON nc_user(company_id, ext_id); CREATE INDEX nc_user_idx_3 ON nc_user(company_id); -- --- User properties table. --- -CREATE TABLE nc_user_property ( - id NUMBER PRIMARY KEY, - user_id NUMBER NOT NULL, - property VARCHAR2(64) NOT NULL, - value VARCHAR2(512) NULL, - created_on DATE DEFAULT sysdate NOT NULL, - last_modified_on DATE DEFAULT sysdate NOT NULL, - CONSTRAINT fk_user_id_user_property FOREIGN KEY (user_id) REFERENCES nc_user(id) -); - -CREATE INDEX nc_user_property_idx1 ON nc_user_property(user_id); - --- -- Pool of password hashes. -- CREATE TABLE passwd_pool ( @@ -125,6 +97,7 @@ CREATE TABLE proc_log ( -- Result parts. res_type VARCHAR2(32) NULL, res_body_gzip CLOB NULL, -- GZIP-ed result body. + res_body_meta CLOB NULL, -- GZIP-ed result meta. intent_id VARCHAR2(256) NULL, error CLOB NULL, -- Probe information for this request. diff --git a/sql/postgres/drop_schema.sql b/sql/postgres/drop_schema.sql index b1ce0b9..f985bae 100644 --- a/sql/postgres/drop_schema.sql +++ b/sql/postgres/drop_schema.sql @@ -16,9 +16,7 @@ -- DROP TABLE IF EXISTS proc_log; -DROP TABLE IF EXISTS nc_user_property; DROP TABLE IF EXISTS nc_user; -DROP TABLE IF EXISTS nc_company_property; DROP TABLE IF EXISTS nc_company; DROP TABLE IF EXISTS passwd_pool; DROP TABLE IF EXISTS feedback; \ No newline at end of file diff --git a/sql/postgres/schema.sql b/sql/postgres/schema.sql index 561418e..8329ed7 100644 --- a/sql/postgres/schema.sql +++ b/sql/postgres/schema.sql @@ -37,6 +37,7 @@ CREATE TABLE nc_company ( postal_code VARCHAR(32), auth_token VARCHAR(64) NOT NULL, auth_token_hash VARCHAR(64) NOT NULL, + properties_gzip TEXT NULL, created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3) ); @@ -46,21 +47,6 @@ CREATE UNIQUE INDEX nc_company_idx_2 ON nc_company(auth_token); CREATE UNIQUE INDEX nc_company_idx_3 ON nc_company(auth_token_hash); -- --- Company properties table. --- -CREATE TABLE nc_company_property ( - id SERIAL PRIMARY KEY, - company_id BIGINT NOT NULL, - property VARCHAR(64) NOT NULL, - value VARCHAR(512) NULL, - created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - FOREIGN KEY (company_id) REFERENCES nc_company(id) -); - -CREATE INDEX nc_company_property_idx1 ON nc_company_property(company_id); - --- -- -- User table. -- @@ -74,6 +60,7 @@ CREATE TABLE nc_user ( last_name VARCHAR(64) NULL, is_admin BOOL NOT NULL, -- Whether or not created with admin token. passwd_salt VARCHAR(64) NULL, + properties_gzip TEXT NULL, created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), FOREIGN KEY (company_id) REFERENCES nc_company(id) @@ -92,21 +79,6 @@ CREATE TABLE passwd_pool ( ); -- --- User properties table. --- -CREATE TABLE nc_user_property ( - id SERIAL PRIMARY KEY, - user_id BIGINT NOT NULL, - property VARCHAR(64) NOT NULL, - value VARCHAR(512) NULL, - created_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - last_modified_on TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(3), - FOREIGN KEY (user_id) REFERENCES nc_user(id) -); - -CREATE INDEX nc_user_property_idx1 ON nc_user_property(user_id); - --- -- Processing log. -- CREATE TABLE proc_log ( @@ -126,6 +98,7 @@ CREATE TABLE proc_log ( -- Result parts. res_type VARCHAR(32) NULL, res_body_gzip TEXT NULL, -- GZIP-ed result body. + res_body_meta TEXT NULL, -- GZIP-ed result body. intent_id VARCHAR(256) NULL, error TEXT NULL, -- Probe information for this request.