<commit_before>package im.actor.server.migrations

import akka.actor.ActorSystem
import im.actor.server.db.DbExtension
import im.actor.server.group.GroupExtension
import im.actor.server.persist
import slick.driver.PostgresDriver

import scala.concurrent.duration._
import scala.concurrent.{ ExecutionContext, Future }

object HiddenGroupMigrator extends Migration {
  override protected def migrationName: String = "PutHiddenGroupsToSQL"

  override protected def migrationTimeout: Duration = 15.minutes

  override protected def startMigration()(implicit system: ActorSystem, db: PostgresDriver.api.Database, ec: ExecutionContext): Future[Unit] = {
    for {
      ids ← db.run(persist.Group.findAllIds)
      _ ← Future.sequence(ids map migrateGroup)
    } yield ()
  }

  private def migrateGroup(id: Int)(implicit system: ActorSystem, ec: ExecutionContext): Future[Unit] = {
    val db = DbExtension(system).db
    val groupExt = GroupExtension(system)
    groupExt.getApiStruct(id, 0) flatMap { group ⇒
      if (group.isHidden.contains(true))
        db.run(persist.Group.makeHidden(id)) map (_ ⇒ ())
      else
        Future.successful(())
    }
  }
}<commit_msg>fix(server): smarter group migrator<commit_after>package im.actor.server.migrations

import akka.actor.{ActorLogging, ActorSystem, PoisonPill, Props}
import akka.persistence.{PersistentActor, RecoveryCompleted}
import im.actor.concurrent.FutureExt._
import im.actor.server.db.DbExtension
import im.actor.server.event.TSEvent
import im.actor.server.group.GroupOffice
import im.actor.server.{persist => p}
import slick.driver.PostgresDriver

import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.{Failure, Success}

object HiddenGroupMigrator extends Migration {

  private case object Migrate

  override protected def migrationName: String = "PutHiddenGroupsToSQL"

  override protected def migrationTimeout: Duration = 15.minutes

  override protected def startMigration()(implicit system: ActorSystem, db: PostgresDriver.api.Database, ec: ExecutionContext): Future[Unit] = {
    for {
      ids ← db.run(p.Group.findAllIds)
      _ ← ftraverse(ids)(migrateGroup)
    } yield ()
  }

  private def migrateGroup(id: Int)(implicit system: ActorSystem, ec: ExecutionContext): Future[Unit] = {
    val promise = Promise[Unit]()
    system.actorOf(Props(new HiddenGroupMigrator(promise, id)), s"hidden_group_migrator_$id")
    promise.future onFailure {
      case e => system.log.error(e, s"Failed to migrate $id")
    }
    promise.future
  }
}

private final class HiddenGroupMigrator(promise: Promise[Unit], groupId: Int) extends PersistentActor with ActorLogging {

  import HiddenGroupMigrator._
  import im.actor.server.group.GroupEvents._
  import context.dispatcher

  val db = DbExtension(context.system).db

  override def persistenceId = GroupOffice.persistenceIdFor(groupId)

  var isHidden = false

  private def migrate(): Unit = {
    if (isHidden) {
      db.run(p.Group.makeHidden(groupId)) onComplete {
        case Failure(e) =>
          promise.failure(e)
          self ! PoisonPill
        case Success(_) =>
          promise.success(())
          self ! PoisonPill
      }
    } else {
      promise.success(())
      context stop self
    }
  }

  def receiveCommand = {
    case Migrate =>
      migrate()
  }

  def receiveRecover = {
    case TSEvent(_, e: Created) =>
      isHidden = e.isHidden.getOrElse(false)
    case RecoveryCompleted =>
      self ! Migrate
  }
}
{'fraction_non_alphanumeric': 0.1020986954055587, 'fraction_numerical': 0.0014180374361883153, 'mean_word_length': 3.8918169209431346, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 10, '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': '6893907', 'n_tokens_mistral': 1096, 'n_tokens_neox': 1053, 'n_words': 247}