<commit_before>package org.extendedmind.db

import java.util.UUID
import scala.collection.JavaConversions.iterableAsScalaIterable
import org.apache.commons.codec.binary.Base64
import org.extendedmind._
import org.extendedmind.Response._
import org.extendedmind.domain._
import org.extendedmind.security._
import org.neo4j.graphdb.Direction
import org.neo4j.graphdb.DynamicRelationshipType
import org.neo4j.graphdb.Node
import org.neo4j.graphdb.traversal.Evaluators
import org.neo4j.graphdb.traversal.TraversalDescription
import org.neo4j.kernel.Traversal
import org.neo4j.scala.DatabaseService
import scala.collection.mutable.ListBuffer
import org.neo4j.index.lucene.ValueContext
import org.neo4j.index.lucene.QueryContext
import org.neo4j.graphdb.Relationship
import spray.util.LoggingContext

trait InviteDatabase extends UserDatabase {

  // PUBLICs

  def postInviteRequest(inviteRequest: InviteRequest): Response[InviteRequestResult] = {
    for {
      info <- createInviteRequestInformation(inviteRequest).right
      setResult <- Right(getSetResult(info._2, true)).right
      inviteRequestResult <- Right(
          InviteRequestResult(
              info._1,
              if (info._1 == USER_RESULT) None else Some(setResult), 
              info._3
          )).right
    } yield inviteRequestResult
  }

  def putNewInviteRequest(inviteRequest: InviteRequest): Response[SetResult] = {
    for {
      ir <- createInviteRequest(inviteRequest).right
      createResponse <- Right(createInviteRequestModifiedIndex(ir)).right
      result <- Right(getSetResult(ir, true)).right
    } yield result
  }

  def putExistingInviteRequest(inviteRequestUUID: UUID, inviteRequest: InviteRequest): Response[Tuple3[SetResult, Node, Long]] = {
    for {
      updatedInviteRequest <- updateInviteRequest(inviteRequestUUID, inviteRequest).right
      result <- Right(getSetResult(updatedInviteRequest._1, false)).right
    } yield (result, updatedInviteRequest._1, updatedInviteRequest._2)
  }

  def createInviteRequestModifiedIndex(inviteRequestNode: Node): Unit = {
    withTx {
      implicit neo =>
        val inviteRequests = neo.gds.index().forNodes("inviteRequests")
        inviteRequests.add(inviteRequestNode, "modified",
          new ValueContext(inviteRequestNode.getProperty("modified").asInstanceOf[Long]).indexNumeric())
    }
  }

  def updateInviteRequestModifiedIndex(inviteRequestNode: Node, oldModified: Long): Unit = {
    withTx {
      implicit neo =>
        val inviteRequests = neo.gds.index().forNodes("inviteRequests")
        inviteRequests.remove(inviteRequestNode, "modified", oldModified)
        inviteRequests.add(inviteRequestNode, "modified",
          new ValueContext(inviteRequestNode.getProperty("modified").asInstanceOf[Long]).indexNumeric())
    }
  }

  def getInviteRequests(): Response[InviteRequests] = {
    withTx {
      implicit neo =>
        val inviteRequests = neo.gds.index().forNodes("inviteRequests")
        val inviteRequestNodeList = inviteRequests.query("modified",
          QueryContext.numericRange("modified", 0, Long.MaxValue).sort("modified")).toList
        if (inviteRequestNodeList.isEmpty) {
          Right(InviteRequests(scala.List()))
        } else {
          Right(InviteRequests(inviteRequestNodeList map (inviteRequestNode => {
            val response = toCaseClass[InviteRequest](inviteRequestNode)
            if (response.isLeft) return Left(response.left.get)
            else response.right.get
          })))
        }
    }
  }

  def getInviteRequestQueueNumber(inviteRequestUUID: UUID): Response[InviteRequestQueueNumber] = {
    withTx {
      implicit neo =>
        for {
          inviteRequestNode <- getNode(inviteRequestUUID, MainLabel.REQUEST).right
          inviteRequestQueueNumber <- getInviteRequestQueueNumber(inviteRequestNode).right
        } yield inviteRequestQueueNumber
    }
  }

  def acceptInviteRequest(userUUID: Option[UUID], inviteRequestUUID: UUID, message: Option[String]): Response[(SetResult, Invite)] = {
    // First get user node result, hard to do in for comprehension
    val userNodeResult: Option[Response[Node]] = 
      if (userUUID.isDefined) Some(getNode(userUUID.get, OwnerLabel.USER))
      else None
    // Handle errors
    if (userNodeResult.isDefined && userNodeResult.get.isLeft){
      return Left(userNodeResult.get.left.get)
    }
    // Get node value
    val userNode: Option[Node] = 
      if (userNodeResult.isDefined) Some(userNodeResult.get.right.get)
      else None

    for {
      ir <- createInvite(userNode, inviteRequestUUID, message).right
      result <- Right(getSetResult(ir._1, true)).right
    } yield (result, ir._2)
  }

  def putExistingInvite(inviteUUID: UUID, invite: Invite): Response[SetResult] = {
    for {
      updatedInvite <- updateInvite(inviteUUID, invite).right
      result <- Right(getSetResult(updatedInvite, false)).right
    } yield result
  }

  def getInvite(code: Long, email: String): Response[Invite] = {
    withTx {
      implicit neo =>
        for {
          inviteNode <- getInviteNode(code, email).right
          invite <- toCaseClass[Invite](inviteNode).right
        } yield invite
    }
  }

  def getInvites(): Response[Invites] = {
    withTx {
      implicit neo =>
        val inviteNodeList = findNodesByLabel(MainLabel.INVITE).toList
        if (inviteNodeList.isEmpty) {
          Right(Invites(scala.List()))
        } else {
          Right(Invites(inviteNodeList map (inviteNode => {
            val response = toCaseClass[Invite](inviteNode)
            if (response.isLeft) return Left(response.left.get)
            else response.right.get
          })))
        }
    }
  }

  def acceptInvite(signUp: SignUp, code: Long, signUpMode: SignUpMode): Response[(SetResult, Option[Long])] = {
    for {
      acceptResult<- acceptInviteNode(signUp, code, signUpMode).right
      result <- Right(getSetResult(acceptResult._1, true)).right
    } yield (result, acceptResult._2)
  }

  def destroyInviteRequest(inviteRequestUUID: UUID): Response[DestroyResult] = {
    withTx {
      implicit neo4j =>
        val inviteRequest = getNode(inviteRequestUUID, MainLabel.REQUEST)
        if (inviteRequest.isLeft) Left(inviteRequest.left.get)
        else {
          if (!inviteRequest.right.get.getRelationships().toList.isEmpty) {
            fail(INVALID_PARAMETER, "Can't delete accepted invite request")
          } else {
            // First delete it from the index
            val inviteRequests = neo4j.gds.index().forNodes("inviteRequests")
            inviteRequests.remove(inviteRequest.right.get)
            // Delete it completely
            inviteRequest.right.get.delete()
            Right(DestroyResult(scala.List(inviteRequestUUID)))
          }
        }
    }
  }

  def rebuildInviteRequestsIndex: Response[CountResult] = {
    withTx {
      implicit neo4j =>
        val inviteRequests = neo4j.gds.index().forNodes("inviteRequests")
        val oldInvitesInIndex = inviteRequests.query("*:*").toList
        oldInvitesInIndex.foreach(inviteRequestNode => {
          inviteRequests.remove(inviteRequestNode)
        })

        // Add all back to index
        val inviteRequestNodes = findNodesByLabel(MainLabel.REQUEST)
        var count = 0
        inviteRequestNodes.foreach(inviteRequestNode => {
          if (inviteRequestNode.getRelationships().toList.isEmpty) {
            createInviteRequestModifiedIndex(inviteRequestNode)
            count += 1
          }
        })
        Right(CountResult(count))
    }
  }

  // PRIVATE

  protected def createInviteRequestInformation(inviteRequest: InviteRequest): Response[(InviteRequestResultType, Node, Option[Int])] = {
    withTx {
      implicit neo =>
        // First check if user
        val userNodeList = findNodesByLabelAndProperty(OwnerLabel.USER, "email", inviteRequest.email).toList
        if (!userNodeList.isEmpty) {
          return Right(USER_RESULT, userNodeList(0), None)
        }
        val inviteNodeList = findNodesByLabelAndProperty(MainLabel.INVITE, "email", inviteRequest.email).toList
        if (!inviteNodeList.isEmpty) {
          return Right(INVITE_RESULT, inviteNodeList(0), None)
        }
        val requestNodeList = findNodesByLabelAndProperty(MainLabel.REQUEST, "email", inviteRequest.email).toList
        if (!requestNodeList.isEmpty) {
          val inviteRequestQueueNumberResponse = getInviteRequestQueueNumber(requestNodeList(0))
          if (inviteRequestQueueNumberResponse.isLeft) Left(inviteRequestQueueNumberResponse.left.get)
          return Right((INVITE_REQUEST_RESULT, requestNodeList(0),
            Some(inviteRequestQueueNumberResponse.right.get.queueNumber)))
        }<commit_msg>Added deleting of duplicates invite request rebuild<commit_after>package org.extendedmind.db

import java.util.UUID
import scala.collection.JavaConversions.iterableAsScalaIterable
import org.apache.commons.codec.binary.Base64
import org.extendedmind._
import org.extendedmind.Response._
import org.extendedmind.domain._
import org.extendedmind.security._
import org.neo4j.graphdb.Direction
import org.neo4j.graphdb.DynamicRelationshipType
import org.neo4j.graphdb.Node
import org.neo4j.graphdb.traversal.Evaluators
import org.neo4j.graphdb.traversal.TraversalDescription
import org.neo4j.kernel.Traversal
import org.neo4j.scala.DatabaseService
import scala.collection.mutable.ListBuffer
import org.neo4j.index.lucene.ValueContext
import org.neo4j.index.lucene.QueryContext
import org.neo4j.graphdb.Relationship
import spray.util.LoggingContext

trait InviteDatabase extends UserDatabase {

  // PUBLICs

  def postInviteRequest(inviteRequest: InviteRequest): Response[InviteRequestResult] = {
    for {
      info <- createInviteRequestInformation(inviteRequest).right
      setResult <- Right(getSetResult(info._2, true)).right
      inviteRequestResult <- Right(
          InviteRequestResult(
              info._1,
              if (info._1 == USER_RESULT) None else Some(setResult), 
              info._3
          )).right
    } yield inviteRequestResult
  }

  def putNewInviteRequest(inviteRequest: InviteRequest): Response[SetResult] = {
    for {
      ir <- createInviteRequest(inviteRequest).right
      createResponse <- Right(createInviteRequestModifiedIndex(ir)).right
      result <- Right(getSetResult(ir, true)).right
    } yield result
  }

  def putExistingInviteRequest(inviteRequestUUID: UUID, inviteRequest: InviteRequest): Response[Tuple3[SetResult, Node, Long]] = {
    for {
      updatedInviteRequest <- updateInviteRequest(inviteRequestUUID, inviteRequest).right
      result <- Right(getSetResult(updatedInviteRequest._1, false)).right
    } yield (result, updatedInviteRequest._1, updatedInviteRequest._2)
  }

  def createInviteRequestModifiedIndex(inviteRequestNode: Node): Unit = {
    withTx {
      implicit neo =>
        val inviteRequests = neo.gds.index().forNodes("inviteRequests")
        inviteRequests.add(inviteRequestNode, "modified",
          new ValueContext(inviteRequestNode.getProperty("modified").asInstanceOf[Long]).indexNumeric())
    }
  }

  def updateInviteRequestModifiedIndex(inviteRequestNode: Node, oldModified: Long): Unit = {
    withTx {
      implicit neo =>
        val inviteRequests = neo.gds.index().forNodes("inviteRequests")
        inviteRequests.remove(inviteRequestNode, "modified", oldModified)
        inviteRequests.add(inviteRequestNode, "modified",
          new ValueContext(inviteRequestNode.getProperty("modified").asInstanceOf[Long]).indexNumeric())
    }
  }

  def getInviteRequests(): Response[InviteRequests] = {
    withTx {
      implicit neo =>
        val inviteRequests = neo.gds.index().forNodes("inviteRequests")
        val inviteRequestNodeList = inviteRequests.query("modified",
          QueryContext.numericRange("modified", 0, Long.MaxValue).sort("modified")).toList
        if (inviteRequestNodeList.isEmpty) {
          Right(InviteRequests(scala.List()))
        } else {
          Right(InviteRequests(inviteRequestNodeList map (inviteRequestNode => {
            val response = toCaseClass[InviteRequest](inviteRequestNode)
            if (response.isLeft) return Left(response.left.get)
            else response.right.get
          })))
        }
    }
  }

  def getInviteRequestQueueNumber(inviteRequestUUID: UUID): Response[InviteRequestQueueNumber] = {
    withTx {
      implicit neo =>
        for {
          inviteRequestNode <- getNode(inviteRequestUUID, MainLabel.REQUEST).right
          inviteRequestQueueNumber <- getInviteRequestQueueNumber(inviteRequestNode).right
        } yield inviteRequestQueueNumber
    }
  }

  def acceptInviteRequest(userUUID: Option[UUID], inviteRequestUUID: UUID, message: Option[String]): Response[(SetResult, Invite)] = {
    // First get user node result, hard to do in for comprehension
    val userNodeResult: Option[Response[Node]] = 
      if (userUUID.isDefined) Some(getNode(userUUID.get, OwnerLabel.USER))
      else None
    // Handle errors
    if (userNodeResult.isDefined && userNodeResult.get.isLeft){
      return Left(userNodeResult.get.left.get)
    }
    // Get node value
    val userNode: Option[Node] = 
      if (userNodeResult.isDefined) Some(userNodeResult.get.right.get)
      else None

    for {
      ir <- createInvite(userNode, inviteRequestUUID, message).right
      result <- Right(getSetResult(ir._1, true)).right
    } yield (result, ir._2)
  }

  def putExistingInvite(inviteUUID: UUID, invite: Invite): Response[SetResult] = {
    for {
      updatedInvite <- updateInvite(inviteUUID, invite).right
      result <- Right(getSetResult(updatedInvite, false)).right
    } yield result
  }

  def getInvite(code: Long, email: String): Response[Invite] = {
    withTx {
      implicit neo =>
        for {
          inviteNode <- getInviteNode(code, email).right
          invite <- toCaseClass[Invite](inviteNode).right
        } yield invite
    }
  }

  def getInvites(): Response[Invites] = {
    withTx {
      implicit neo =>
        val inviteNodeList = findNodesByLabel(MainLabel.INVITE).toList
        if (inviteNodeList.isEmpty) {
          Right(Invites(scala.List()))
        } else {
          Right(Invites(inviteNodeList map (inviteNode => {
            val response = toCaseClass[Invite](inviteNode)
            if (response.isLeft) return Left(response.left.get)
            else response.right.get
          })))
        }
    }
  }

  def acceptInvite(signUp: SignUp, code: Long, signUpMode: SignUpMode): Response[(SetResult, Option[Long])] = {
    for {
      acceptResult<- acceptInviteNode(signUp, code, signUpMode).right
      result <- Right(getSetResult(acceptResult._1, true)).right
    } yield (result, acceptResult._2)
  }

  def destroyInviteRequest(inviteRequestUUID: UUID): Response[DestroyResult] = {
    withTx {
      implicit neo4j =>
        val inviteRequest = getNode(inviteRequestUUID, MainLabel.REQUEST)
        if (inviteRequest.isLeft) Left(inviteRequest.left.get)
        else {
          if (!inviteRequest.right.get.getRelationships().toList.isEmpty) {
            fail(INVALID_PARAMETER, "Can't delete accepted invite request")
          } else {
            // First delete it from the index
            val inviteRequests = neo4j.gds.index().forNodes("inviteRequests")
            inviteRequests.remove(inviteRequest.right.get)
            // Delete it completely
            inviteRequest.right.get.delete()
            Right(DestroyResult(scala.List(inviteRequestUUID)))
          }
        }
    }
  }

  def rebuildInviteRequestsIndex: Response[CountResult] = {
    withTx {
      implicit neo4j =>
        val inviteRequests = neo4j.gds.index().forNodes("inviteRequests")
        val oldInvitesInIndex = inviteRequests.query("*:*").toList
        oldInvitesInIndex.foreach(inviteRequestNode => {
          inviteRequests.remove(inviteRequestNode)
        })

        // Add all back to index
        val inviteRequestNodes = findNodesByLabel(MainLabel.REQUEST)
        var count = 0
        val inviteRequestUUIDMap = scala.collection.mutable.HashMap.empty[String,Node]

        inviteRequestNodes.foreach(inviteRequestNode => {
          
          val uuid = inviteRequestNode.getProperty("uuid").asInstanceOf[String]
          // Because of our duplicate UUID bug, check that this isn't on the list already
          if (inviteRequestUUIDMap.contains(uuid)){
            val duplicateNode =
              if (inviteRequestNode.getRelationships().toList.isEmpty){
                // Prefer earlier
                inviteRequestNode
              }else {
                inviteRequestUUIDMap.get(uuid).get
              }
            // Delete duplicate
            if (duplicateNode.getRelationships().toList.isEmpty){
              println("Deleting invite request for " + duplicateNode.getProperty("email").asInstanceOf[String] 
                        + " has duplicate uuid " 
                        + UUIDUtils.getUUID(duplicateNode.getProperty("uuid").asInstanceOf[String])
                        + " with id " + duplicateNode.getId())
              duplicateNode.delete
            }
          }else {
            inviteRequestUUIDMap.put(uuid, inviteRequestNode)
            if (inviteRequestNode.getRelationships().toList.isEmpty) {
              createInviteRequestModifiedIndex(inviteRequestNode)
              count += 1
            }
          }       
        })
        Right(CountResult(count))
    }
  }

  // PRIVATE

  protected def createInviteRequestInformation(inviteRequest: InviteRequest): Response[(InviteRequestResultType, Node, Option[Int])] = {
    withTx {
      implicit neo =>
        // First check if user
        val userNodeList = findNodesByLabelAndProperty(OwnerLabel.USER, "email", inviteRequest.email).toList
        if (!userNodeList.isEmpty) {
          return Right(USER_RESULT, userNodeList(0), None)
        }
        val inviteNodeList = findNodesByLabelAndProperty(MainLabel.INVITE, "email", inviteRequest.email).toList
        if (!inviteNodeList.isEmpty) {
          return Right(INVITE_RESULT, inviteNodeList(0), None)
        }
        val requestNodeList = findNodesByLabelAndProperty(MainLabel.REQUEST, "email", inviteRequest.email).toList
        if (!requestNodeList.isEmpty) {
          val inviteRequestQueueNumberResponse = getInviteRequestQueueNumber(requestNodeList(0))
          if (inviteRequestQueueNumberResponse.isLeft) Left(inviteRequestQueueNumberResponse.left.get)
          return Right((INVITE_REQUEST_RESULT, requestNodeList(0),
            Some(inviteRequestQueueNumberResponse.right.get.queueNumber)))
        }
{'fraction_non_alphanumeric': 0.09937255322571996, 'fraction_numerical': 0.0037539550597951413, 'mean_word_length': 3.0725049137366236, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4229280', 'n_tokens_mistral': 5326, 'n_tokens_neox': 5288, 'n_words': 939}