text: import logging
  
  from django.utils.timezone import now
  from django.utils.text import slugify
  
  import six
  
  from awx.main.models.base import PERM_INVENTORY_SCAN, PERM_INVENTORY_DEPLOY
  from awx.main import utils
  
  
  logger = logging.getLogger('awx.main.migrations')
  
  
  def _create_fact_scan_project(ContentType, Project, org):
      ct = ContentType.objects.get_for_model(Project)
      name = u"Tower Fact Scan - {}".format(org.name if org else "No Organization")
      proj = Project(name=name,
                     scm_url='https://github.com/ansible/awx-facts-playbooks',
                     scm_type='git',
                     scm_update_on_launch=True,
                     scm_update_cache_timeout=86400,
                     organization=org,
                     created=now(),
                     modified=now(),
                     polymorphic_ctype=ct)
      proj.save()
  
      slug_name = slugify(six.text_type(name)).replace(u'-', u'_')
      proj.local_path = u'_%d__%s' % (int(proj.pk), slug_name)
  
      proj.save()
      return proj
  
  
  def _create_fact_scan_projects(ContentType, Project, orgs):
      return {org.id : _create_fact_scan_project(ContentType, Project, org) for org in orgs}
  
  
  def _get_tower_scan_job_templates(JobTemplate):
      return JobTemplate.objects.filter(job_type=PERM_INVENTORY_SCAN, project__isnull=True) \
                                .prefetch_related('inventory__organization')
  
  
  def _get_orgs(Organization, job_template_ids):
      return Organization.objects.filter(inventories__jobtemplates__in=job_template_ids).distinct()
  
  
  def _migrate_scan_job_templates(apps):
      JobTemplate = apps.get_model('main', 'JobTemplate')
      Organization = apps.get_model('main', 'Organization')
      ContentType = apps.get_model('contenttypes', 'ContentType')
      Project = apps.get_model('main', 'Project')
  
      project_no_org = None
  
      # A scan job template with a custom project will retain the custom project.
      JobTemplate.objects.filter(job_type=PERM_INVENTORY_SCAN, project__isnull=False).update(use_fact_cache=True, job_type=PERM_INVENTORY_DEPLOY)
  
      # Scan jobs templates using Tower's default scan playbook will now point at
      # the same playbook but in a github repo.
      jts = _get_tower_scan_job_templates(JobTemplate)
      if jts.count() == 0:
          return
  
      orgs = _get_orgs(Organization, jts.values_list('id'))
      if orgs.count() == 0:
          return
  
      org_proj_map = _create_fact_scan_projects(ContentType, Project, orgs)
      for jt in jts:
          if jt.inventory and jt.inventory.organization:
              jt.project_id = org_proj_map[jt.inventory.organization.id].id
          # Job Templates without an Organization; through related Inventory
          else:
              if not project_no_org:
                  project_no_org = _create_fact_scan_project(ContentType, Project, None)
              jt.project_id = project_no_org.id
          jt.job_type = PERM_INVENTORY_DEPLOY
          jt.playbook = "scan_facts.yml"
          jt.use_fact_cache = True
          jt.save()
  
  
  def migrate_scan_job_templates(apps, schema_editor):
      _migrate_scan_job_templates(apps)
  
  
  def remove_scan_type_nodes(apps, schema_editor):
      WorkflowJobTemplateNode = apps.get_model('main', 'WorkflowJobTemplateNode')
      WorkflowJobNode = apps.get_model('main', 'WorkflowJobNode')
  
      for cls in (WorkflowJobNode, WorkflowJobTemplateNode):
          for node in cls.objects.iterator():
              prompts = node.char_prompts
              if prompts.get('job_type', None) == 'scan':
                  log_text = '{} set job_type to scan, which was deprecated in 3.2, removing.'.format(cls)
                  if cls == WorkflowJobNode:
                      logger.info(log_text)
                  else:
                      logger.debug(log_text)
                  prompts.pop('job_type')
                  node.char_prompts = prompts
                  node.save()
  
  
  def remove_legacy_fact_cleanup(apps, schema_editor):
      SystemJobTemplate = apps.get_model('main', 'SystemJobTemplate')
      for job in SystemJobTemplate.objects.filter(job_type='cleanup_facts').all():
          for sched in job.schedules.all():
              sched.delete()
          job.delete()
  