2017-07-20 14:10:03 +00:00
import logging
2019-07-17 18:24:54 +00:00
from django . conf import settings
2017-07-20 14:10:03 +00:00
from django . db import models
from django . db . models import Q
from django . db . models import signals
from django . dispatch import receiver
from django . utils import timezone
from guardian . models import GroupObjectPermissionBase
from guardian . models import UserObjectPermissionBase
from guardian . shortcuts import get_perms_for_model , assign_perm
2021-08-06 15:33:43 +00:00
from django . utils . translation import gettext_lazy as _ , gettext
from django . db import transaction
2017-07-20 14:10:03 +00:00
from app import pending_actions
from nodeodm import status_codes
logger = logging . getLogger ( ' app.logger ' )
class Project ( models . Model ) :
2020-12-18 17:32:44 +00:00
owner = models . ForeignKey ( settings . AUTH_USER_MODEL , on_delete = models . PROTECT , help_text = _ ( " The person who created the project " ) , verbose_name = _ ( " Owner " ) )
name = models . CharField ( max_length = 255 , help_text = _ ( " A label used to describe the project " ) , verbose_name = _ ( " Name " ) )
description = models . TextField ( default = " " , blank = True , help_text = _ ( " More in-depth description of the project " ) , verbose_name = _ ( " Description " ) )
created_at = models . DateTimeField ( default = timezone . now , help_text = _ ( " Creation date " ) , verbose_name = _ ( " Created at " ) )
deleting = models . BooleanField ( db_index = True , default = False , help_text = _ ( " Whether this project has been marked for deletion. Projects that have running tasks need to wait for tasks to be properly cleaned up before they can be deleted. " ) , verbose_name = _ ( " Deleting " ) )
2017-07-20 14:10:03 +00:00
def delete ( self , * args ) :
# No tasks?
if self . task_set . count ( ) == 0 :
# Just delete normally
logger . info ( " Deleted project {} " . format ( self . id ) )
super ( ) . delete ( * args )
else :
# Need to remove all tasks before we can remove this project
2018-02-15 21:23:29 +00:00
# which will be deleted by workers after pending actions
2017-07-20 14:10:03 +00:00
# have been completed
self . task_set . update ( pending_action = pending_actions . REMOVE )
self . deleting = True
self . save ( )
logger . info ( " Tasks pending, set project {} deleting flag " . format ( self . id ) )
def __str__ ( self ) :
return self . name
def tasks ( self ) :
return self . task_set . only ( ' id ' )
def get_map_items ( self ) :
return [ task . get_map_items ( ) for task in self . task_set . filter (
status = status_codes . COMPLETED
) . filter ( Q ( orthophoto_extent__isnull = False ) | Q ( dsm_extent__isnull = False ) | Q ( dtm_extent__isnull = False ) )
. only ( ' id ' , ' project_id ' ) ]
2021-08-06 15:33:43 +00:00
def duplicate ( self ) :
try :
with transaction . atomic ( ) :
project = Project . objects . get ( pk = self . pk )
project . pk = None
project . name = gettext ( ' Copy of %(task)s ' ) % { ' task ' : self . name }
project . created_at = timezone . now ( )
project . save ( )
project . refresh_from_db ( )
for task in self . task_set . all ( ) :
new_task = task . duplicate ( set_new_name = False )
if not new_task :
raise Exception ( " Failed to duplicate {} " . format ( new_task ) )
# Move/Assign to new duplicate
new_task . project = project
new_task . save ( )
return project
except Exception as e :
logger . warning ( " Cannot duplicate project: {} " . format ( str ( e ) ) )
return False
2017-07-20 14:10:03 +00:00
2020-12-18 17:32:44 +00:00
class Meta :
verbose_name = _ ( " Project " )
verbose_name_plural = _ ( " Projects " )
2017-07-20 14:10:03 +00:00
@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 ) :
2018-03-11 14:06:09 +00:00
content_object = models . ForeignKey ( Project , on_delete = models . CASCADE )
2017-07-20 14:10:03 +00:00
class ProjectGroupObjectPermission ( GroupObjectPermissionBase ) :
2018-03-11 14:06:09 +00:00
content_object = models . ForeignKey ( Project , on_delete = models . CASCADE )