Exemplo n.º 1
0
 def __init__(self, wiki, name=''):
     Watchable.__init__(self)
     qon.karma.HasKarma.__init__(self)
     self.wiki = wiki
     self.outbound_references = None
     self.inbound_references = None
     self.name = clean_page_name(name)
     self.versions = PersistentList()
     self.blog = Blog(self)
     self.locked_by_user = None
     self.__cached_html = PersistentCache(self._update_html_cache)
     self.__cached_html2 = PersistentCache(self._update_html2_cache)
     self.new_revision(force_new=1)
Exemplo n.º 2
0
class WikiPage(QonPersistent, Watchable, qon.karma.HasKarma, IHasBlog):

    persistenceVersion = 4

    def __init__(self, wiki, name=''):
        Watchable.__init__(self)
        qon.karma.HasKarma.__init__(self)
        self.wiki = wiki
        self.outbound_references = None
        self.inbound_references = None
        self.name = clean_page_name(name)
        self.versions = PersistentList()
        self.blog = Blog(self)
        self.locked_by_user = None
        self.__cached_html = PersistentCache(self._update_html_cache)
        self.__cached_html2 = PersistentCache(self._update_html2_cache)
        self.new_revision(force_new=1)
        
    def upgradeToVersion4(self):
        self.inbound_references = None
        self.version_upgrade_done()

    def upgradeToVersion3(self):
        self.__cached_html2 = PersistentCache(self._update_html2_cache)
        self.version_upgrade_done()

    def upgradeToVersion2(self):
        self.__cached_html = PersistentCache(self._update_html_cache)
        self.version_upgrade_done()

    def upgradeToVersion1(self):
        self.blog.ihb = self
        self.version_upgrade_done()
        
    def __repr__(self):
        return '<%s object at 0x%x: %s>' % (self.__module__ + '.' + self.__class__.__name__,
            id(self), self.name or "*no name*")

    def new_revision(self, set_date=True, author=None, title='', raw='', force_new=0):
        """Create a new revision for this page.
        
        Check to make sure that the new text is actually different
        from the latest revision.  If it's not, then don't bother creating a
        new revision."""
        if force_new or (self.versions[-1].get_raw() != raw):
            w = WikiVersion(page=self, author=author, title=title, raw=raw)
            if set_date:
                w.set_date(datetime.utcnow())
            self.versions.append(w)
            
            self.watchable_changed(w.date)
            if author:
                author.karma_activity_credit()
                
            # before invalidating referring pages, we want to 
            # update the html cache, which has the side effect
            # of updating the outbound references.
            self.invalidate_html_cache()
            unused_html = self.get_cached_html()

            # may seem useless for new pages, but we could be creating
            # a new page that was referred to from another page somewhere
            self._invalidate_referring_pages()
            
            self._p_changed = 1
            
    def _invalidate_referring_pages(self, all_groups=0):
        """Invalidate HTML cache of pages which refer to this one."""

        # we changed default behavior to not scan all groups when invalidating.
        # this means that cross-group links for new pages after this change
        # will not be accurate, until the page(s) linking to the new page
        # is itself modified.

        refs = self.wiki.references_to(self, all_groups=all_groups)
        for p in refs:
            p.invalidate_html_cache()
        
    def latest_edit_by(self, user):
        """Return latest edit by user, or None."""
        rvers = self.versions[:]
        rvers.reverse()
        for version in rvers:
            if version.author is user:
                return version
        return None
        
    def get_comments(self):
        """Return list of comments (BlogItems)."""
        blog_item = self.blog.get_item(0)
        if blog_item:
            return blog_item.get_comments()
        else:
            return []
        
    def get_revision(self, rev_id):
        """Return revision index rev_id or None."""
        rev_id = max(0, rev_id)
        try:
            rev = self.versions[rev_id]
        except IndexError:
            rev = None
        return rev

    def revision_index(self, version):
        """Return revision index of version, or raise ValueError."""
        return self.versions.index(version)

    def merge_revisions(self, base, old, new):
        """Merge the newest revision with older revision, off of base. Returns (merged text, exit_code) or None.
        
        Base may be -1 to signify empty text.
        Exit code is 0 for no conflicts, or 1 if conflicts exist.
        """
        if len(self.versions) < 2:
            return None

        if base == -1:
            base_text = ''
        else:
            base_text = self.versions[base].get_raw()

        old_text = self.versions[old].get_raw()
        new_text = self.versions[new].get_raw()

        merger = Merger(base_text, old_text, new_text)
        merged = merger.merge('Revision %d' % base,
            'Revision %d' % old,
            'Revision %d' % new,
            )

        if not merged:
            return None

        exit_code = 0
        if merger.has_conflicts():
            exit_code = 1

        return (merged, exit_code)


    def watchable_name(self):
        #return self.wiki.group.name + ' ' + self.versions[-1].title
        return self.versions[-1].title or self.name
        
    def watchable_changed(self, now=None):
        # wiki changed, too
        Watchable.watchable_changed(self, now)
        self.wiki.watchable_changed(now)

    def watchable_modified_date(self):
        return self.watchable_last_change()
        
    def last_modified(self):
        sys.stderr.write('WARNING: using deprecated qon.wiki.WikiPage.last_modified.')
        return self.watchable_last_change()

    def who_has_lock(self):
        return self.locked_by_user

    def can_edit(self, user):
        """ A page is editable if either it's not locked by anybody,
        or if the requesting user is the one who holds the lock, or
        if the user is allowed to edit within the group"""
        
        # user must be logged in to edit
        if not user:
            return False
            
        # check lock
        if (self.locked_by_user) and (self.locked_by_user is not user) and (not self.can_manage(user)):
            return False
            
        if self.wiki.group.can_edit(user):
            return True
        
        return False
        
    def can_show(self):
        """Return False if this item should be suppressed due to feedback score."""
        if self.get_karma_score() < qon.karma.min_karma_to_show:
            return False
        return True
        

    def can_lock(self, user):
        """ For now, let only a group owner lock/unlock a page.
        In the future, we may want to consider allowing the original
        page author to lock/unlock as well."""
        return self.wiki.group.is_owner(user)

    def lock(self, user):
        if self.can_lock(user):
            self.locked_by_user = user

    def unlock(self, user):
        if self.can_lock(user):
            self.locked_by_user = None
            
    def can_get_karma_from(self, other):
        return other is not None
        
    # HTML cache methods
    
    def add_html_dependency(self, target):
        """Adds target as something self depends on for its HTML cache."""
        self.__cached_html.add_dependency(target)
        self.__cached_html2.add_dependency(target)
        
    def invalidate_html_cache(self):
        self.__cached_html.flush()
        self.__cached_html2.flush()
        
    def get_cached_html(self):
        return self.__cached_html.get()

    def get_cached_html2(self):
        return self.__cached_html2.get()

    def _update_html_cache(self):
        
        v = self.versions[-1]
        html = v.raw_to_html(v.get_raw())
        
        # take this opportunity to update the page's outbound references
        if hasattr(v, '_v_references'):
            self.set_outbound_references(v._v_references)
            del v._v_references
            
        return html

    def _update_html2_cache(self):
        
        v = self.versions[-1]
        html = v.raw_to_html(v.get_raw(), suppress_tooltip=1)
        
        return html

    def disable_cache(self):
        self.__cached_html.disable_cache()
        self.__cached_html2.disable_cache()

    def cache_disabled(self):
        return self.__cached_html.cache_disabled() or self.__cached_html2.cache_disabled()
  
    def get_ref(self):
        """Return a reference (group, page_name) to this page, for use in
        outbound/inbound references."""
        return (self.wiki.group, self.name)
            
    def set_outbound_references(self, new_out_refs):
        """Record new outbound references."""

        # filter non-existent cross-group page refs out of new_out_refs
        # this interacts with the change that no longer scans all groups
        # for references to new pages. if a cross-group link existed to a new
        # page, this method (pre-filtering) would have neglected to add the inbound
        # link from the cross-group reference, even if both pages had been edited.
        l = []
        for r in new_out_refs:
            group_name, page_name = r
            if not group_name:
                l.append(r)
            else:
                page = _ref_to_page(r, self.wiki.group)
                if page:
                    l.append(r)
        new_out_refs = l

        # get old outbound refs
        old_out_refs = self.outbound_references or []

        # get two lists: items that used to be outbound references but
        # are no longer (old_not_new), and new outbound references that
        # weren't there before (new_not_old)
        old_not_new, new_not_old = xor_lists(old_out_refs, new_out_refs)

        # pre-fill reference to me
        me_ref = self.get_ref()

        # invalidate inbound references of pages that we no longer refer to
        for ref in old_not_new:
            page = _ref_to_page(ref, self.wiki.group)
            if page:    # added by Alex
                page.remove_inbound_reference(me_ref)

        # add inbound references for pages we've added outbound links to
        for ref in new_not_old:
            page = _ref_to_page(ref, self.wiki.group)
            if page:    # could be ref to new page
                page.add_inbound_reference(me_ref)

        # record new outbound references
        self.outbound_references = PersistentList()
        self.outbound_references.extend(new_out_refs)

    def remove_inbound_reference(self, ref):
        if self.inbound_references is not None:
            if ref in self.inbound_references:
                self.inbound_references.remove(ref)

    def add_inbound_reference(self, ref):
        if self.inbound_references is not None:
            if ref not in self.inbound_references:
                self.inbound_references.append(ref)

    # IHasBlog methods not implemented by other base classes
    
    def can_manage(self, user):
        """Who can manage this blog? Group owners."""
        return self.wiki.group.is_owner(user)
        
    def can_read(self, user):
        return self.wiki.can_read(user)
        
    def can_delete_item(self, item):
        """Can't delete item 0, which holds page comments."""
        if self.blog.get_item(0) is item:
            return False
        return True
        
    def can_create_item(self):
        """Users aren't allowed to create new topics in wiki pages."""
        return False
    
    def is_accepted(self):
        return self.wiki.group.is_accepted()
    
    def get_owners(self):
        return self.wiki.group.get_owners()
    
    def is_owner(self, user):
        return self.wiki.group.is_owner(user)
        
    def get_title(self):
        # this is here and in BlogItem
        return self.versions[-1].title or self.name
    
    def get_blog(self):
        return self.blog
    
    def get_wiki(self):
        return self.wiki
    
    def get_name(self):
        return self.name
    
    def get_all_owners(self):
        return self.get_owners()
    
    def get_all_blogs(self):
        return [self.blog]
        
    def get_member_list(self):
        return self.wiki.group.get_member_list()