<commit_before>from os.path import join
from datetime import datetime
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _, get_language
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
from django.shortcuts import get_object_or_404
from publisher import MpttPublisher
from publisher.errors import PublisherCantPublish
from cms.utils.urlutils import urljoin
from cms import settings
from cms.models.managers import PageManager, PagePermissionsPermissionManager
from cms.models import signals as cms_signals
from cms.utils.page import get_available_slug
from cms.exceptions import NoHomeFound



class Page(MpttPublisher):
    """
    A simple hierarchical page model
    """
    MODERATOR_CHANGED = 0
    MODERATOR_NEED_APPROVEMENT = 1
    MODERATOR_NEED_DELETE_APPROVEMENT = 2
    MODERATOR_APPROVED = 10
    # special case - page was approved, but some of page parents if not approved yet
    MODERATOR_APPROVED_WAITING_FOR_PARENTS = 11
    
    moderator_state_choices = (
        (MODERATOR_CHANGED, _('changed')),
        (MODERATOR_NEED_APPROVEMENT, _('req. app.')),
        (MODERATOR_NEED_DELETE_APPROVEMENT, _('delete')),
        (MODERATOR_APPROVED, _('approved')),
        (MODERATOR_APPROVED_WAITING_FOR_PARENTS, _('app. par.')),
    )
    created_by = models.CharField(_("created by"), max_length=70)
    changed_by = models.CharField(_("changed by"), max_length=70)
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
    creation_date = models.DateTimeField(editable=False, default=datetime.now)
    publication_date = models.DateTimeField(_("publication date"), null=True, blank=True, help_text=_('When the page should go live. Status must be "Published" for page to go live.'), db_index=True)
    publication_end_date = models.DateTimeField(_("publication end date"), null=True, blank=True, help_text=_('When to expire the page. Leave empty to never expire.'), db_index=True)
    login_required = models.BooleanField(_('login required'), default=False)
    in_navigation = models.BooleanField(_("in navigation"), default=True, db_index=True)
    soft_root = models.BooleanField(_("soft root"), db_index=True, default=False, help_text=_("All ancestors will not be displayed in the navigation"))
    reverse_id = models.CharField(_("id"), max_length=40, db_index=True, blank=True, null=True, help_text=_("An unique identifier that is used with the page_url templatetag for linking to this page"))
    navigation_extenders = models.CharField(_("navigation extenders"), max_length=80, db_index=True, blank=True, null=True, choices=settings.CMS_NAVIGATION_EXTENDERS)
    published = models.BooleanField(_("is published"), blank=True)
    
    template = models.CharField(_("template"), max_length=100, choices=settings.CMS_TEMPLATES, help_text=_('The template used to render the content.'))
    site = models.ForeignKey(Site, help_text=_('The site the page is accessible at.'), verbose_name=_("site"))
    
    moderator_state = models.SmallIntegerField(_('moderator state'), choices=moderator_state_choices, default=MODERATOR_NEED_APPROVEMENT, blank=True)
    
    level = models.PositiveIntegerField(db_index=True, editable=False)
    lft = models.PositiveIntegerField(db_index=True, editable=False)
    rght = models.PositiveIntegerField(db_index=True, editable=False)
    tree_id = models.PositiveIntegerField(db_index=True, editable=False)
    
    
    # Managers
    objects = PageManager()
    permissions = PagePermissionsPermissionManager()

    class Meta:
        verbose_name = _('page')
        verbose_name_plural = _('pages')
        ordering = ('tree_id', 'lft')
        app_label = 'cms'
    
    class PublisherMeta:
        exclude_fields_append = ['moderator_state']
    
    def __unicode__(self):
        slug = self.get_slug(fallback=True)
        if slug is None:
            return u'' # otherwise we get unicode decode errors
        else:
            return slug
        
    
    def move_page(self, target, position='first-child'):
        """Called from admin interface when page is moved. Should be used on
        all the places which are changing page position. Used like an interface
        to mptt, but after move is done page_moved signal is fired.
        """
        self.move_to(target, position)
        # fire signal
        from cms.models.moderatormodels import PageModeratorState
        self.force_moderation_action = PageModeratorState.ACTION_MOVE
        cms_signals.page_moved.send(sender=Page, instance=self) #titles get saved before moderation
        self.save(change_state=True) # always save the page after move, because of publisher
        
        
    def copy_page(self, target, site, position='first-child', copy_permissions=True, copy_moderation=True):
        """
        copy a page and all its descendants to a new location
        
        Doesn't checks for add page permissions anymore, this is done in PageAdmin.
        """
        from cms.utils.moderator import update_moderation_message
        
        descendants = [self] + list(self.get_descendants().order_by('-rght'))
        tree = [target]
        level_dif = self.level - target.level - 1
        first = True
        for page in descendants:
            new_level = page.level - level_dif
            dif = new_level - tree[-1].level 
            if dif < 0:
                tree = tree[:dif-1]
           
            titles = list(page.title_set.all())
            plugins = list(page.cmsplugin_set.all().order_by('tree_id', '-rght'))
            
            origin_id = page.id
            # IMPORTANT NOTE: self gets changed in next few lines to page!!
            
            page.pk = None
            page.level = None
            page.rght = None
            page.lft = None
            page.tree_id = None
            page.status = Page.MODERATOR_NEED_APPROVEMENT
            page.parent = tree[-1]
            page.publisher_public_id = None
            page.reverse_id = None
            page.save()
            
            update_moderation_message(page, _('Page was copied.'))
            # copy moderation, permissions if necessary
            if settings.CMS_PERMISSION and copy_permissions:
                from cms.models.permissionmodels import PagePermission
                for permission in PagePermission.objects.filter(page__id=origin_id):
                    permission.pk = None
                    permission.page = page
                    permission.save()
            
            if settings.CMS_MODERATOR and copy_moderation:
                from cms.models.moderatormodels import PageModerator
                for moderator in PageModerator.objects.filter(page__id=origin_id):
                    moderator.pk = None
                    moderator.page = page
                    moderator.save()
            
            if first:
                first = False
                page.move_to(target, position)
            page.site = site
            page.save()
            for title in titles:
                title.pk = None
                title.publisher_public_id = None
                title.page = page
                title.slug = get_available_slug(title)
                title.save()
            ptree = []
            for p in plugins:<commit_msg>if you copy a page it will keep its reverse_id if it is copied to a other site and that reverse_id does not exist there yet.<commit_after>from os.path import join
from datetime import datetime
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _, get_language
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
from django.shortcuts import get_object_or_404
from publisher import MpttPublisher
from publisher.errors import PublisherCantPublish
from cms.utils.urlutils import urljoin
from cms import settings
from cms.models.managers import PageManager, PagePermissionsPermissionManager
from cms.models import signals as cms_signals
from cms.utils.page import get_available_slug
from cms.exceptions import NoHomeFound



class Page(MpttPublisher):
    """
    A simple hierarchical page model
    """
    MODERATOR_CHANGED = 0
    MODERATOR_NEED_APPROVEMENT = 1
    MODERATOR_NEED_DELETE_APPROVEMENT = 2
    MODERATOR_APPROVED = 10
    # special case - page was approved, but some of page parents if not approved yet
    MODERATOR_APPROVED_WAITING_FOR_PARENTS = 11
    
    moderator_state_choices = (
        (MODERATOR_CHANGED, _('changed')),
        (MODERATOR_NEED_APPROVEMENT, _('req. app.')),
        (MODERATOR_NEED_DELETE_APPROVEMENT, _('delete')),
        (MODERATOR_APPROVED, _('approved')),
        (MODERATOR_APPROVED_WAITING_FOR_PARENTS, _('app. par.')),
    )
    created_by = models.CharField(_("created by"), max_length=70)
    changed_by = models.CharField(_("changed by"), max_length=70)
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
    creation_date = models.DateTimeField(editable=False, default=datetime.now)
    publication_date = models.DateTimeField(_("publication date"), null=True, blank=True, help_text=_('When the page should go live. Status must be "Published" for page to go live.'), db_index=True)
    publication_end_date = models.DateTimeField(_("publication end date"), null=True, blank=True, help_text=_('When to expire the page. Leave empty to never expire.'), db_index=True)
    login_required = models.BooleanField(_('login required'), default=False)
    in_navigation = models.BooleanField(_("in navigation"), default=True, db_index=True)
    soft_root = models.BooleanField(_("soft root"), db_index=True, default=False, help_text=_("All ancestors will not be displayed in the navigation"))
    reverse_id = models.CharField(_("id"), max_length=40, db_index=True, blank=True, null=True, help_text=_("An unique identifier that is used with the page_url templatetag for linking to this page"))
    navigation_extenders = models.CharField(_("navigation extenders"), max_length=80, db_index=True, blank=True, null=True, choices=settings.CMS_NAVIGATION_EXTENDERS)
    published = models.BooleanField(_("is published"), blank=True)
    
    template = models.CharField(_("template"), max_length=100, choices=settings.CMS_TEMPLATES, help_text=_('The template used to render the content.'))
    site = models.ForeignKey(Site, help_text=_('The site the page is accessible at.'), verbose_name=_("site"))
    
    moderator_state = models.SmallIntegerField(_('moderator state'), choices=moderator_state_choices, default=MODERATOR_NEED_APPROVEMENT, blank=True)
    
    level = models.PositiveIntegerField(db_index=True, editable=False)
    lft = models.PositiveIntegerField(db_index=True, editable=False)
    rght = models.PositiveIntegerField(db_index=True, editable=False)
    tree_id = models.PositiveIntegerField(db_index=True, editable=False)
    
    
    # Managers
    objects = PageManager()
    permissions = PagePermissionsPermissionManager()

    class Meta:
        verbose_name = _('page')
        verbose_name_plural = _('pages')
        ordering = ('tree_id', 'lft')
        app_label = 'cms'
    
    class PublisherMeta:
        exclude_fields_append = ['moderator_state']
    
    def __unicode__(self):
        slug = self.get_slug(fallback=True)
        if slug is None:
            return u'' # otherwise we get unicode decode errors
        else:
            return slug
        
    
    def move_page(self, target, position='first-child'):
        """Called from admin interface when page is moved. Should be used on
        all the places which are changing page position. Used like an interface
        to mptt, but after move is done page_moved signal is fired.
        """
        self.move_to(target, position)
        # fire signal
        from cms.models.moderatormodels import PageModeratorState
        self.force_moderation_action = PageModeratorState.ACTION_MOVE
        cms_signals.page_moved.send(sender=Page, instance=self) #titles get saved before moderation
        self.save(change_state=True) # always save the page after move, because of publisher
        
        
    def copy_page(self, target, site, position='first-child', copy_permissions=True, copy_moderation=True):
        """
        copy a page and all its descendants to a new location
        
        Doesn't checks for add page permissions anymore, this is done in PageAdmin.
        """
        from cms.utils.moderator import update_moderation_message
        
        descendants = [self] + list(self.get_descendants().order_by('-rght'))
        tree = [target]
        level_dif = self.level - target.level - 1
        first = True
        
        all_reverse_ids = Page.objects.filter(site=site, reverse_id__gt='').values('reverse_id').values()
        
        for page in descendants:
            new_level = page.level - level_dif
            dif = new_level - tree[-1].level 
            if dif < 0:
                tree = tree[:dif-1]
           
            titles = list(page.title_set.all())
            plugins = list(page.cmsplugin_set.all().order_by('tree_id', '-rght'))
            
            origin_id = page.id
            # IMPORTANT NOTE: self gets changed in next few lines to page!!
            
            page.pk = None
            page.level = None
            page.rght = None
            page.lft = None
            page.tree_id = None
            page.status = Page.MODERATOR_NEED_APPROVEMENT
            page.parent = tree[-1]
            page.publisher_public_id = None
            if page.reverse_id in all_reverse_ids:
                # reverse_id already exists for some page on the target site
                page.reverse_id = None
            page.save()
            
            update_moderation_message(page, _('Page was copied.'))
            # copy moderation, permissions if necessary
            if settings.CMS_PERMISSION and copy_permissions:
                from cms.models.permissionmodels import PagePermission
                for permission in PagePermission.objects.filter(page__id=origin_id):
                    permission.pk = None
                    permission.page = page
                    permission.save()
            
            if settings.CMS_MODERATOR and copy_moderation:
                from cms.models.moderatormodels import PageModerator
                for moderator in PageModerator.objects.filter(page__id=origin_id):
                    moderator.pk = None
                    moderator.page = page
                    moderator.save()
            
            if first:
                first = False
                page.move_to(target, position)
            page.site = site
            page.save()
            for title in titles:
                title.pk = None
                title.publisher_public_id = None
                title.page = page
                title.slug = get_available_slug(title)
                title.save()
            ptree = []
            for p in plugins:
{'fraction_non_alphanumeric': 0.08515413558650736, 'fraction_numerical': 0.0034325698065878936, 'mean_word_length': 2.692420180355837, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3674779', 'n_tokens_mistral': 4331, 'n_tokens_neox': 4234, 'n_words': 1111}