<commit_before>package com.softwaremill.codebrag.service.user

import java.util.UUID
import java.util.concurrent.{Executors, TimeUnit}

import com.softwaremill.codebrag.common.EventBus
import com.softwaremill.codebrag.dao.user.UserDAO
import com.softwaremill.codebrag.domain.{Authentication, User, UserToken}
import com.typesafe.scalalogging.slf4j.Logging

trait Authenticator {

  val scheduledExecutor = Executors.newSingleThreadScheduledExecutor()

  def userDAO: UserDAO

  def authenticateWithToken(token: String): Option[User] = {
    userDAO.findByToken(token).filter(_.active)
  }

  def findByLogin(login: String): Option[User] = {
    userDAO.findByLowerCasedLogin(login).filter(_.active)
  }

  def deleteOldSoonAndCreateNewToken(user: User, token: Option[UserToken]) = {

    val newToken = UserToken(UUID.randomUUID().toString)
    token match {
      case Some(t) =>
        // When many requests are fired with the same token,
        // it's possible that first one replaces token, and the second one hits the
        // server with old token when it's already replaced.
        // That's why we don't delete the old token immidiately, but after some time.
        scheduledExecutor.schedule(new Runnable {
          override def run() = {
            val tokensWithoutUsed = user.tokens.diff(Set(t))
            val userWithoutUsedToken = user.copy(tokens = tokensWithoutUsed + newToken)
            userDAO.modifyUser(userWithoutUsedToken)
          }
        },
        5,
        TimeUnit.SECONDS)

      case None => userDAO.modifyUser(user.copy(tokens = user.tokens + newToken))
    }
<commit_msg>Adds removal of expired tokens<commit_after>package com.softwaremill.codebrag.service.user

import java.util.UUID
import java.util.concurrent.{Executors, TimeUnit}

import com.softwaremill.codebrag.common.EventBus
import com.softwaremill.codebrag.dao.user.UserDAO
import com.softwaremill.codebrag.domain.{Authentication, User, UserToken}
import com.typesafe.scalalogging.slf4j.Logging

trait Authenticator {

  val scheduledExecutor = Executors.newSingleThreadScheduledExecutor()

  def userDAO: UserDAO

  def authenticateWithToken(token: String): Option[User] = {
    userDAO.findByToken(token)
      .filter(_.active)
      .map(removeExpiredTokens)
      //If used token expired, we don't let the user in
      .filter(_.tokens.exists(_.token == token))
  }

  private def removeExpiredTokens(user: User) = {
    val userWithoutExpiredTokens = user.copy(tokens = user.tokens.filterNot(_.expireDate.isBeforeNow))
    userDAO.modifyUser(userWithoutExpiredTokens)
    userWithoutExpiredTokens
  }

  def findByLogin(login: String): Option[User] = {
    userDAO.findByLowerCasedLogin(login).filter(_.active)
  }

  def deleteOldSoonAndCreateNewToken(user: User, token: Option[UserToken]) = {

    val newToken = UserToken(UUID.randomUUID().toString)
    token match {
      case Some(t) =>
        // When many requests are fired with the same token,
        // it's possible that first one replaces token, and the second one hits the
        // server with old token when it's already replaced.
        // That's why we don't delete the old token immediately, but after some time.
        scheduledExecutor.schedule(new Runnable {
          override def run() = {
            val tokensWithoutUsed = user.tokens.diff(Set(t))
            val userWithoutUsedToken = user.copy(tokens = tokensWithoutUsed + newToken)
            userDAO.modifyUser(userWithoutUsedToken)
          }
        },
        5,
        TimeUnit.SECONDS)

      case None => userDAO.modifyUser(user.copy(tokens = user.tokens + newToken))
    }

{'fraction_non_alphanumeric': 0.09436038514442915, 'fraction_numerical': 0.0011004126547455295, 'mean_word_length': 3.375451263537906, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '7664880', 'n_tokens_mistral': 1101, 'n_tokens_neox': 1073, 'n_words': 250}