2016-09-21 20:04:47 +00:00
from __future__ import unicode_literals
2016-08-10 20:23:17 +00:00
from django . db import models
2016-10-04 20:36:08 +00:00
from django . db . models import signals
2016-09-09 21:37:04 +00:00
from django . utils import timezone
from django . contrib . auth . models import User
2016-09-10 15:24:16 +00:00
from django . contrib . postgres import fields
2016-09-21 20:04:47 +00:00
from nodeodm . models import ProcessingNode
2016-10-04 20:36:08 +00:00
from django . dispatch import receiver
from guardian . shortcuts import get_perms_for_model , assign_perm
from guardian . models import UserObjectPermissionBase
from guardian . models import GroupObjectPermissionBase
2016-10-13 20:28:32 +00:00
from django . db import transaction
2016-09-10 15:24:16 +00:00
def assets_directory_path ( taskId , projectId , filename ) :
2016-10-17 17:19:32 +00:00
# files will be uploaded to MEDIA_ROOT/project/<id>/task/<id>/<filename>
return ' project/ {0} /task/ {1} / {2} ' . format ( projectId , taskId , filename )
2016-09-10 15:24:16 +00:00
2016-09-09 21:37:04 +00:00
class Project ( models . Model ) :
owner = models . ForeignKey ( User , on_delete = models . PROTECT , help_text = " The person who created the project " )
name = models . CharField ( max_length = 255 , help_text = " A label used to describe the project " )
2016-10-04 20:36:08 +00:00
description = models . TextField ( null = True , blank = True , help_text = " More in-depth description of the project " )
2016-09-09 21:37:04 +00:00
created_at = models . DateTimeField ( default = timezone . now , help_text = " Creation date " )
def __str__ ( self ) :
return self . name
2016-10-13 16:21:12 +00:00
def tasks ( self , pk = None ) :
2016-10-12 22:18:37 +00:00
return Task . objects . filter ( project = self ) ;
2016-10-04 20:36:08 +00:00
class Meta :
permissions = (
( ' view_project ' , ' Can view project ' ) ,
)
@receiver ( signals . post_save , sender = Project , dispatch_uid = " project_post_save " )
def project_post_save ( sender , instance , created , * * kwargs ) :
"""
Automatically assigns all permissions to the owner . If the owner changes
it ' s up to the user/developer to remove the previous owner ' s permissions .
"""
for perm in get_perms_for_model ( sender ) . all ( ) :
assign_perm ( perm . codename , instance . owner , instance )
class ProjectUserObjectPermission ( UserObjectPermissionBase ) :
content_object = models . ForeignKey ( Project )
class ProjectGroupObjectPermission ( GroupObjectPermissionBase ) :
content_object = models . ForeignKey ( Project )
2016-09-10 15:24:16 +00:00
def gcp_directory_path ( task , filename ) :
return assets_directory_path ( task . id , task . project . id , filename )
2016-09-09 21:37:04 +00:00
class Task ( models . Model ) :
2016-09-10 15:24:16 +00:00
STATUS_CODES = (
( 10 , ' QUEUED ' ) ,
( 20 , ' RUNNING ' ) ,
( 30 , ' FAILED ' ) ,
( 40 , ' COMPLETED ' ) ,
( 50 , ' CANCELED ' )
)
2016-10-13 16:21:12 +00:00
uuid = models . CharField ( max_length = 255 , null = True , blank = True , help_text = " Identifier of the task (as returned by OpenDroneMap ' s REST API) " )
2016-09-10 15:24:16 +00:00
project = models . ForeignKey ( Project , on_delete = models . CASCADE , help_text = " Project that this task belongs to " )
2016-10-12 22:18:37 +00:00
name = models . CharField ( max_length = 255 , null = True , blank = True , help_text = " A label for the task " )
2016-10-25 20:04:24 +00:00
processing_lock = models . BooleanField ( default = False , help_text = " A flag indicating whether this task is currently locked for processing. When this flag is turned on, the task is in the middle of a processing step. " )
2016-09-09 21:37:04 +00:00
processing_time = models . IntegerField ( default = - 1 , help_text = " Number of milliseconds that elapsed since the beginning of this task (-1 indicates that no information is available) " )
2016-10-12 22:18:37 +00:00
processing_node = models . ForeignKey ( ProcessingNode , null = True , blank = True , help_text = " Processing node assigned to this task (or null if this task has not been associated yet) " )
status = models . IntegerField ( choices = STATUS_CODES , null = True , blank = True , help_text = " Current status of the task " )
options = fields . JSONField ( default = dict ( ) , blank = True , help_text = " Options that are being used to process this task " )
console_output = models . TextField ( null = True , blank = True , help_text = " Console output of the OpenDroneMap ' s process " )
ground_control_points = models . FileField ( null = True , blank = True , upload_to = gcp_directory_path , help_text = " Optional Ground Control Points file to use for processing " )
2016-10-25 20:04:24 +00:00
2016-09-09 21:37:04 +00:00
# georeferenced_model
# orthophoto
# textured_model
# mission
created_at = models . DateTimeField ( default = timezone . now , help_text = " Creation date " )
2016-08-10 20:23:17 +00:00
2016-09-09 21:37:04 +00:00
def __str__ ( self ) :
2016-10-13 20:28:32 +00:00
return ' Task ID: {} ' . format ( self . id )
@staticmethod
def create_from_images ( images , project ) :
'''
Create a new task from a set of input images ( such as the ones coming from request . FILES ) .
This will happen inside a transaction so if one of the images
fails to load , the task will not be created .
'''
with transaction . atomic ( ) :
task = Task . objects . create ( project = project )
for image in images :
ImageUpload . objects . create ( task = task , image = image )
return task
# In case of error
return None
2016-09-10 15:24:16 +00:00
2016-10-25 20:04:24 +00:00
def process ( self ) :
if not self . uuid and self . processing_node :
print ( " Processing... {} " . format ( self ) )
import time
time . sleep ( 30 )
print ( " Done! {} " . format ( self ) )
2016-10-13 16:21:12 +00:00
class Meta :
permissions = (
( ' view_task ' , ' Can view task ' ) ,
)
2016-09-10 15:24:16 +00:00
2016-10-13 20:28:32 +00:00
def image_directory_path ( imageUpload , filename ) :
2016-09-10 15:24:16 +00:00
return assets_directory_path ( imageUpload . task . id , imageUpload . task . project . id , filename )
class ImageUpload ( models . Model ) :
task = models . ForeignKey ( Task , on_delete = models . CASCADE , help_text = " Task this image belongs to " )
image = models . ImageField ( upload_to = image_directory_path , help_text = " File uploaded by a user " )
def __str__ ( self ) :
return self . image . name