# Path: ncdjango/models.py
# class ProcessingJob(models.Model):
#     """ An active, completed, or failed geoprocessing job. """
# 
#     uuid = models.CharField(max_length=36, default=uuid.uuid4, db_index=True)
#     job = models.CharField(max_length=100)
#     user = models.ForeignKey(USER_MODEL, null=True, on_delete=models.SET_NULL)
#     user_ip = models.CharField(max_length=32)
#     created = models.DateTimeField(auto_now_add=True)
#     celery_id = models.CharField(max_length=100)
#     inputs = models.TextField(null=False, default="{}")
#     outputs = models.TextField(null=False, default="{}")
# 
#     @property
#     def status(self):
#         """ The status of the celery task for this job. """
# 
#         return AsyncResult(self.celery_id).status.lower()
# 
# Path: ncdjango/geoprocessing/celery_tasks.py
# @task(bind=True)
# def run_job(self, job_name, inputs):
#     job_info = REGISTERED_JOBS[job_name]
#     results_renderer = job_info.get('results_renderer')
# 
#     if isinstance(results_renderer, str):
#         try:
#             module_name, class_name = results_renderer.rsplit('.', 1)
#             module = import_module(module_name)
#             results_renderer = getattr(module, class_name)
#         except (ImportError, ValueError, AttributeError):
#             raise ImproperlyConfigured('Could not import {}'.format(results_renderer))
# 
#     if not any((results_renderer is None, callable(results_renderer), isinstance(results_renderer, RasterRenderer))):
#         raise ImproperlyConfigured('Invalid renderer: {}'.format(results_renderer))
# 
#     t = get_task_instance(job_name)
#     results = t(**process_web_inputs(t, copy.copy(inputs)))
#     publish_raster_results = job_info.get('publish_raster_results', False)
# 
#     job = ProcessingJob.objects.get(celery_id=self.request.id)
#     job.outputs = json.dumps(process_web_outputs(results, job, publish_raster_results, results_renderer))
#     job.save()
# 
# Path: ncdjango/geoprocessing/utils.py
# REGISTERED_JOBS = getattr(settings, 'NC_REGISTERED_JOBS', {})
# 
# def get_task_instance(job_name):
#     if job_name not in REGISTERED_JOBS:
#         return None
# 
#     job_info = REGISTERED_JOBS[job_name]
# 
#     if not isinstance(job_info, dict) or 'type' not in job_info:
#         raise ImproperlyConfigured('NC_REGISTERED_JOBS configuration is invalid.')
# 
#     if job_info['type'] == 'task':
#         class_path = job_info.get('task')
#         if not class_path:
#             raise ImproperlyConfigured('Registered job {} does not specify a task.'.format(job_name))
# 
#         try:
#             module_name, class_name = class_path.rsplit('.', 1)
#             module = import_module(module_name)
#             cls = getattr(module, class_name)
#         except (ImportError, ValueError, AttributeError):
#             raise ImproperlyConfigured('{} is not a valid task.'.format(class_path))
# 
#         return cls()
#     elif job_info['type'] == 'workflow':
#         path = job_info.get('path')
#         if not path or not os.path.isfile(path):
#             raise ImproperlyConfigured('The workflow {} does not exist.'.format(path))
# 
#         with open(path, 'r') as f:
#             return Workflow.from_json(f.read())
#     else:
#         raise ImproperlyConfigured('Invalid job type: {}'.format(job_info['type']))


import json
from rest_framework import serializers
from ncdjango.models import ProcessingJob
from .celery_tasks import run_job
from .utils import REGISTERED_JOBS, get_task_instance

    def validate_inputs(self, value):
        if value:
            try:
                return json.loads(value, strict=False)
            except ValueError:
                raise serializers.ValidationError('Invalid input JSON')

        return {}

    def validate(self, data):
        task = get_task_instance(data['job'])
        missing_params = set(x.name for x in task.inputs if x.required).difference(set(data['inputs'].keys()))

        if missing_params:
            raise serializers.ValidationError('Missing task inputs: {}'.format(','.join(missing_params)))

        return data

    def create(self, validated_data):
        result = run_job.delay(validated_data['job'], validated_data['inputs'])
        request = self.context['request']

        # Get real IP address if request has been forwarded
        forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if forwarded_for:
            ip_address = forwarded_for.split(',', 1)[0].strip()
        else:
            ip_address = request.META.get('REMOTE_ADDR')


# Path: ncdjango/models.py
# class ProcessingJob(models.Model):
#     """ An active, completed, or failed geoprocessing job. """
# 
#     uuid = models.CharField(max_length=36, default=uuid.uuid4, db_index=True)
#     job = models.CharField(max_length=100)
#     user = models.ForeignKey(USER_MODEL, null=True, on_delete=models.SET_NULL)
#     user_ip = models.CharField(max_length=32)
#     created = models.DateTimeField(auto_now_add=True)
#     celery_id = models.CharField(max_length=100)
#     inputs = models.TextField(null=False, default="{}")
#     outputs = models.TextField(null=False, default="{}")
# 
#     @property
#     def status(self):
#         """ The status of the celery task for this job. """
# 
#         return AsyncResult(self.celery_id).status.lower()
# 
# Path: ncdjango/geoprocessing/celery_tasks.py
# @task(bind=True)
# def run_job(self, job_name, inputs):
#     job_info = REGISTERED_JOBS[job_name]
#     results_renderer = job_info.get('results_renderer')
# 
#     if isinstance(results_renderer, str):
#         try:
#             module_name, class_name = results_renderer.rsplit('.', 1)
#             module = import_module(module_name)
#             results_renderer = getattr(module, class_name)
#         except (ImportError, ValueError, AttributeError):
#             raise ImproperlyConfigured('Could not import {}'.format(results_renderer))
# 
#     if not any((results_renderer is None, callable(results_renderer), isinstance(results_renderer, RasterRenderer))):
#         raise ImproperlyConfigured('Invalid renderer: {}'.format(results_renderer))
# 
#     t = get_task_instance(job_name)
#     results = t(**process_web_inputs(t, copy.copy(inputs)))
#     publish_raster_results = job_info.get('publish_raster_results', False)
# 
#     job = ProcessingJob.objects.get(celery_id=self.request.id)
#     job.outputs = json.dumps(process_web_outputs(results, job, publish_raster_results, results_renderer))
#     job.save()
# 
# Path: ncdjango/geoprocessing/utils.py
# REGISTERED_JOBS = getattr(settings, 'NC_REGISTERED_JOBS', {})
# 
# def get_task_instance(job_name):
#     if job_name not in REGISTERED_JOBS:
#         return None
# 
#     job_info = REGISTERED_JOBS[job_name]
# 
#     if not isinstance(job_info, dict) or 'type' not in job_info:
#         raise ImproperlyConfigured('NC_REGISTERED_JOBS configuration is invalid.')
# 
#     if job_info['type'] == 'task':
#         class_path = job_info.get('task')
#         if not class_path:
#             raise ImproperlyConfigured('Registered job {} does not specify a task.'.format(job_name))
# 
#         try:
#             module_name, class_name = class_path.rsplit('.', 1)
#             module = import_module(module_name)
#             cls = getattr(module, class_name)
#         except (ImportError, ValueError, AttributeError):
#             raise ImproperlyConfigured('{} is not a valid task.'.format(class_path))
# 
#         return cls()
#     elif job_info['type'] == 'workflow':
#         path = job_info.get('path')
#         if not path or not os.path.isfile(path):
#             raise ImproperlyConfigured('The workflow {} does not exist.'.format(path))
# 
#         with open(path, 'r') as f:
#             return Workflow.from_json(f.read())
#     else:
#         raise ImproperlyConfigured('Invalid job type: {}'.format(job_info['type']))


# Path: ncdjango/geoprocessing/serializers.py
import json
from rest_framework import serializers
from ncdjango.models import ProcessingJob
from .celery_tasks import run_job
from .utils import REGISTERED_JOBS, get_task_instance


    def validate_inputs(self, value):
        if value:
            try:
                return json.loads(value, strict=False)
            except ValueError:
                raise serializers.ValidationError('Invalid input JSON')

        return {}

    def validate(self, data):
        task = get_task_instance(data['job'])
        missing_params = set(x.name for x in task.inputs if x.required).difference(set(data['inputs'].keys()))

        if missing_params:
            raise serializers.ValidationError('Missing task inputs: {}'.format(','.join(missing_params)))

        return data

    def create(self, validated_data):
        result = run_job.delay(validated_data['job'], validated_data['inputs'])
        request = self.context['request']

        # Get real IP address if request has been forwarded
        forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if forwarded_for:
            ip_address = forwarded_for.split(',', 1)[0].strip()
        else:
            ip_address = request.META.get('REMOTE_ADDR')


        return ProcessingJob.objects.create(