<commit_before>/*
 * Copyright 2016 OrgSync.
 *
 * Licensed 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 com.orgsync.oskr.events.messages.parts

import com.orgsync.oskr.events.ChannelTemplateMap
import com.orgsync.oskr.events.messages.Message
import com.orgsync.oskr.events.streams.delivery.TemplateCache
import org.json4s.JsonAST._

final case class TemplateSet(
  base        : ChannelTemplateMap,
  digestBase  : ChannelTemplateMap,
  digestLayout: ChannelTemplateMap
) {
  def renderBase(
    address: ChannelAddress,
    message: Message,
    cache  : TemplateCache
  ): Option[JValue] = renderBaseTemplate(
    base, address, message, message.partData, cache
  )

  def renderDigest(
    address : ChannelAddress,
    messages: List[Message],
    cache   : TemplateCache
  ): Option[JValue] = {
    val data = messages.flatMap(message => renderBaseTemplate(
      digestBase, address, message, message.partData, cache
    ))

    val partIds = messages.flatMap(_.partIds)

    messages.headOption.flatMap(message => renderLayoutTemplate(
      digestLayout, address, message.recipient, JArray(data), partIds, cache
    ))
  }

  private def renderBaseTemplate(
    templates: ChannelTemplateMap,
    address  : ChannelAddress,
    message  : Message,
    data     : JArray,
    cache    : TemplateCache
  ): Option[JValue] = {
    val template = templates.get(address.channel)
    val partIDs = JArray(message.partIds.map(id => JString(id.toString)))
    val tags = JArray(message.tags.map(JString).toList)

    val value = JObject(List(
      ("recipient",    message.recipient.data),
      ("data",         data),
      ("address",      JString(address.address)),
      ("senderIds",    JArray(message.senderIds.map(JString).toList)),
      ("messageId",    JString(message.id.toString)),
      ("recipientId",  JString(message.recipient.id)),
      ("channel",      JString(address.channel.name)),
      ("sentInterval", JString(message.sentInterval.toString)),
      ("tags",         tags),
      ("partIds",      partIDs),
      ("deliveryId",   JString(address.deliveryId.get.toString))
    ))

    template.map(t => renderTemplate(t, value, cache))
  }

  private def renderLayoutTemplate(
    templates: ChannelTemplateMap,
    address  : ChannelAddress,
    recipient: Recipient,
    data     : JArray,
    partIds  : List[String],
    cache    : TemplateCache

  ): Option[JValue] = {
    val template = templates.get(address.channel)

    val value = JObject(List(
      ("recipient",   recipient.data),
      ("data",        data),
      ("address",     JString(address.address)),
      ("recipientId", JString(recipient.id)),
      ("channel",     JString(address.channel.name)),
      ("partIds",     JArray(partIds.map(JString))),
      ("deliveryId",  JString(address.deliveryId.get.toString))
    ))

    template.map(t => renderTemplate(t, value, cache))
  }

  private def renderTemplate(
    template: JValue,
    data    : JObject,
    cache   : TemplateCache
  ): JValue = {
    template.transform {
      case JObject(List((templateName: String, JString(s)))) =>
        JString(renderTemplateString(templateName, s, data, cache))
    }
  }
<commit_msg>Basic template error handling<commit_after>/*
 * Copyright 2016 OrgSync.
 *
 * Licensed 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 com.orgsync.oskr.events.messages.parts

import com.orgsync.oskr.events.ChannelTemplateMap
import com.orgsync.oskr.events.messages.Message
import com.orgsync.oskr.events.streams.delivery.TemplateCache
import org.json4s.JsonAST._

import scala.util.Try

final case class TemplateSet(
  base        : ChannelTemplateMap,
  digestBase  : ChannelTemplateMap,
  digestLayout: ChannelTemplateMap
) {
  def renderBase(
    address: ChannelAddress,
    message: Message,
    cache  : TemplateCache
  ): Option[JValue] = renderBaseTemplate(
    base, address, message, message.partData, cache
  )

  def renderDigest(
    address : ChannelAddress,
    messages: List[Message],
    cache   : TemplateCache
  ): Option[JValue] = {
    val data = messages.flatMap(message => renderBaseTemplate(
      digestBase, address, message, message.partData, cache
    ))

    val partIds = messages.flatMap(_.partIds)

    messages.headOption.flatMap(message => renderLayoutTemplate(
      digestLayout, address, message.recipient, JArray(data), partIds, cache
    ))
  }

  private def renderBaseTemplate(
    templates: ChannelTemplateMap,
    address  : ChannelAddress,
    message  : Message,
    data     : JArray,
    cache    : TemplateCache
  ): Option[JValue] = {
    val template = templates.get(address.channel)
    val partIDs = JArray(message.partIds.map(id => JString(id.toString)))
    val tags = JArray(message.tags.map(JString).toList)

    val value = JObject(List(
      ("recipient",    message.recipient.data),
      ("data",         data),
      ("address",      JString(address.address)),
      ("senderIds",    JArray(message.senderIds.map(JString).toList)),
      ("messageId",    JString(message.id.toString)),
      ("recipientId",  JString(message.recipient.id)),
      ("channel",      JString(address.channel.name)),
      ("sentInterval", JString(message.sentInterval.toString)),
      ("tags",         tags),
      ("partIds",      partIDs),
      ("deliveryId",   JString(address.deliveryId.get.toString))
    ))

    template.flatMap(t => Try(renderTemplate(t, value, cache)).toOption)
  }

  private def renderLayoutTemplate(
    templates: ChannelTemplateMap,
    address  : ChannelAddress,
    recipient: Recipient,
    data     : JArray,
    partIds  : List[String],
    cache    : TemplateCache

  ): Option[JValue] = {
    val template = templates.get(address.channel)

    val value = JObject(List(
      ("recipient",   recipient.data),
      ("data",        data),
      ("address",     JString(address.address)),
      ("recipientId", JString(recipient.id)),
      ("channel",     JString(address.channel.name)),
      ("partIds",     JArray(partIds.map(JString))),
      ("deliveryId",  JString(address.deliveryId.get.toString))
    ))

    template.flatMap(t => Try(renderTemplate(t, value, cache)).toOption)
  }

  private def renderTemplate(
    template: JValue,
    data    : JObject,
    cache   : TemplateCache
  ): JValue = {
    template.transform {
      case JObject(List((templateName: String, JString(s)))) =>
        JString(renderTemplateString(templateName, s, data, cache))
    }
  }

{'fraction_non_alphanumeric': 0.11687441361747755, 'fraction_numerical': 0.0024125452352231603, 'mean_word_length': 3.281124497991968, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7152170', 'n_tokens_mistral': 2199, 'n_tokens_neox': 2154, 'n_words': 521}