<s> import copy <EOL> from django . db import models <EOL> from django . utils import timezone <EOL> from django . utils . functional import cached_property <EOL> from django . utils . encoding import python_2_unicode_compatible <EOL> from django . db . models . deletion import ProtectedError <EOL> from django . conf import settings <EOL> from django . template . defaultfilters import date as date_format <EOL> from widgy . db . fields import WidgyField <EOL> from widgy . models . base import Node <EOL> from widgy . utils import QuerySet , unset_pks <EOL> @ python_2_unicode_compatible <EOL> class VersionCommit ( models . Model ) : <EOL> tracker = models . ForeignKey ( '<STR_LIT>' , related_name = '<STR_LIT>' ) <EOL> parent = models . ForeignKey ( '<STR_LIT>' , null = True , on_delete = models . PROTECT ) <EOL> root_node = WidgyField ( on_delete = models . PROTECT ) <EOL> author = models . ForeignKey ( getattr ( settings , '<STR_LIT>' , '<STR_LIT>' ) , <EOL> null = True , on_delete = models . SET_NULL ) <EOL> created_at = models . DateTimeField ( auto_now_add = True ) <EOL> message = models . TextField ( blank = True , null = True ) <EOL> publish_at = models . DateTimeField ( default = timezone . now ) <EOL> class Meta : <EOL> app_label = '<STR_LIT>' <EOL> @ property <EOL> def is_published ( self ) : <EOL> return self . publish_at <= timezone . now ( ) <EOL> def __str__ ( self ) : <EOL> if self . message : <EOL> subject = "<STR_LIT>" % self . message . strip ( ) . split ( '<STR_LIT:\n>' ) [ <NUM_LIT:0> ] <EOL> else : <EOL> subject = '<STR_LIT>' <EOL> date = date_format ( self . created_at , '<STR_LIT>' ) <EOL> return '<STR_LIT>' % ( self . id , date , subject ) <EOL> class VersionTracker ( models . Model ) : <EOL> commit_model = VersionCommit <EOL> head = models . ForeignKey ( '<STR_LIT>' , null = True , on_delete = models . PROTECT , unique = True ) <EOL> working_copy = models . ForeignKey ( Node , on_delete = models . PROTECT , unique = True ) <EOL> class Meta : <EOL> app_label = '<STR_LIT>' <EOL> class VersionTrackerQuerySet ( QuerySet ) : <EOL> def orphan ( self ) : <EOL> """<STR_LIT>""" <EOL> filters = { } <EOL> for rel_obj in ( self . model . _meta . get_all_related_objects ( ) + <EOL> self . model . _meta . get_all_related_many_to_many_objects ( ) ) : <EOL> if not issubclass ( rel_obj . field . model , VersionCommit ) : <EOL> name = rel_obj . field . related_query_name ( ) <EOL> filters [ name + '<STR_LIT>' ] = True <EOL> return self . filter ( ** filters ) <EOL> def published ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . filter ( commits__publish_at__lte = timezone . now ( ) ) . distinct ( ) <EOL> objects = VersionTrackerQuerySet . as_manager ( ) <EOL> def commit ( self , user = None , ** kwargs ) : <EOL> self . head = self . commit_model . objects . create ( <EOL> parent = self . head , <EOL> author = user , <EOL> root_node = self . working_copy . clone_tree ( ) , <EOL> tracker = self , <EOL> ** kwargs <EOL> ) <EOL> self . save ( ) <EOL> return self . head <EOL> def revert_to ( self , commit , user = None , ** kwargs ) : <EOL> self . head = self . commit_model . objects . create ( <EOL> parent = self . head , <EOL> author = user , <EOL> root_node = commit . root_node , <EOL> tracker = self , <EOL> ** kwargs <EOL> ) <EOL> old_working_copy = self . working_copy <EOL> self . working_copy = commit . root_node . clone_tree ( freeze = False ) <EOL> self . save ( ) <EOL> old_working_copy . content . delete ( ) <EOL> return self . head <EOL> def reset ( self ) : <EOL> old_working_copy = self . working_copy <EOL> self . working_copy = self . head . root_node . clone_tree ( freeze = False ) <EOL> self . save ( ) <EOL> try : <EOL> old_working_copy . content . delete ( ) <EOL> except ProtectedError : <EOL> pass <EOL> def commit_is_ready ( self , commit ) : <EOL> """<STR_LIT>""" <EOL> return commit . is_published <EOL> def get_published_node ( self , request ) : <EOL> for commit in self . get_history ( ) : <EOL> if self . commit_is_ready ( commit ) : <EOL> return commit . root_node <EOL> return None <EOL> def get_history ( self ) : <EOL> """<STR_LIT>""" <EOL> commit = self . head <EOL> while commit : <EOL> yield commit <EOL> commit = commit . parent <EOL> def get_history_list ( self ) : <EOL> """<STR_LIT>""" <EOL> commit_dict = dict ( ( i . id , i ) for i in self . commits . select_related ( '<STR_LIT>' , '<STR_LIT>' ) ) <EOL> res = [ ] <EOL> commit_id = self . head_id <EOL> while commit_id : <EOL> commit = commit_dict [ commit_id ] <EOL> commit . tracker = self <EOL> commit . parent = commit_dict . get ( commit . parent_id ) <EOL> res . append ( commit ) <EOL> commit_id = commit . parent_id <EOL> return res <EOL> def has_changes ( self ) : <EOL> if not self . head : <EOL> return True <EOL> else : <EOL> newest_tree = self . head . root_node <EOL> Node . prefetch_trees ( self . working_copy , newest_tree ) <EOL> return not self . working_copy . trees_equal ( newest_tree ) <EOL> def delete ( self ) : <EOL> commits = self . get_history_list ( ) <EOL> self . head = None <EOL> self . save ( ) <EOL> trees_to_delete = set ( [ self . working_copy ] ) <EOL> for commit in commits : <EOL> trees_to_delete . add ( commit . root_node ) <EOL> commit . delete ( ) <EOL> super ( VersionTracker , self ) . delete ( ) <EOL> for root_node in trees_to_delete : <EOL> Node . get_tree ( root_node ) . update ( is_frozen = False ) <EOL> root_node . content . delete ( ) <EOL> @ classmethod <EOL> def get_owner_related_names ( cls ) : <EOL> """<STR_LIT>""" <EOL> for rel_obj in cls . _meta . get_all_related_objects ( ) : <EOL> if isinstance ( rel_obj . field , WidgyField ) : <EOL> yield rel_obj . get_accessor_name ( ) <EOL> @ cached_property <EOL> def owners ( self ) : <EOL> return [ owner <EOL> for attr in self . get_owner_related_names ( ) <EOL> for owner in getattr ( self , attr ) . all ( ) ] <EOL> def clone ( self ) : <EOL> vt = copy . copy ( self ) <EOL> vt . working_copy = vt . working_copy . clone_tree ( freeze = False ) <EOL> commits = list ( self . _commits_to_clone ( ) ) <EOL> unset_pks ( vt ) <EOL> vt . head = None <EOL> vt . save ( ) <EOL> for commit in commits : <EOL> commit . tracker = vt <EOL> commit . parent = vt . head <EOL> unset_pks ( commit ) <EOL> commit . save ( ) <EOL> vt . head = commit <EOL> vt . save ( ) <EOL> return vt <EOL> def _commits_to_clone ( self ) : <EOL> return self . commits . order_by ( '<STR_LIT:id>' ) </s>
