view backend/couchdb/CouchDbBackend.py @ 217:bb3c851b18b1

add source file endcoding header
author Dirk Olmes <dirk@xanthippe.ping.de>
date Sun, 27 Apr 2014 05:33:34 +0200
parents b0de75d57e78
children 699d8f1cebd4
line wrap: on
line source

# -*- coding: utf-8 -*-
from FeedUpdater import FeedUpdater
from Preferences import Preferences
from backend.AbstractBackend import AbstractBackend
from backend.couchdb import CouchDb
from backend.couchdb.Feed import Feed
from backend.couchdb.FeedEntry import FeedEntry
import couchdb
import logging

class CouchDbBackend(AbstractBackend):
    '''
    Backend that uses CouchDB for persistence
    '''

    def __init__(self):
        CouchDb.init()
        server = self._initServer()
        self.database = server[CouchDb.database]
        self.prefs = None

    def _initServer(self):
        if CouchDb.database_url is not None:
            return couchdb.Server(CouchDb.database_url)
        else:
            return couchdb.Server()

    def preferences(self):
        if self.prefs is None:
            self.prefs = Preferences(self.database)
        return self.prefs

    #
    # handling of feeds
    #

    def getFeeds(self):
        if self.preferences().showOnlyUnreadFeeds():
            self.feeds = self._getUnreadFeeds()
        else:
            # make sure that the results are actually fetched into memory, otherwise we'll pass
            # a ViewResults instance around which is not what we want
            self.feeds = list(Feed.all(self.database))
        return self.feeds

    def _getUnreadFeeds(self):
        viewResults = self.database.view(CouchDb.feedsWithUnreadEntries(), group=True)
        feedsWithUnreadEntries = []
        for row in viewResults:
            feed = Feed.load(self.database, row["key"])
            # see https://issues.apache.org/jira/browse/COUCHDB-1279
            # it's possible that the view references documents that have already been deleted
            if feed is not None:
                feedsWithUnreadEntries.append(feed)
        return feedsWithUnreadEntries

    def _retrieveEntriesForSelectedFeed(self, hideReadEntries):
        viewResults = FeedEntry.entriesForFeed(self.selectedFeed, self.database)
        if hideReadEntries:
            filterFunc = lambda feedEntry: feedEntry.read == False
            viewResults = filter(filterFunc, viewResults)
        return viewResults

    def markSelectedFeedAsRead(self):
        for feedEntry in self.entriesForSelectedFeed():
            feedEntry.markRead(self.database)

    #
    # handling of the selected feed entry
    #

    def _markSelectedFeedEntryRead(self):
        self.selectedFeedEntry.markRead(self.database)

    def toggleSelectedFeedEntryRead(self):
        self.selectedFeedEntry.toggleRead(self.database)


    def createFeed(self, url):
        feed = Feed.create(url)
        feed.store(self.database)
        FeedUpdater(self.database, self.preferences()).update(feed)

    def updateFeed(self, feed, changes):
        for key in changes.keys():
            feed[key] = changes[key]
        feed.store(self.database)

    def deleteSelectedFeed(self):
        viewResults = self.database.view(CouchDb.feedEntriesByFeed(), key=self.selectedFeed.id)
        for row in viewResults:
            del self.database[row.id]
        del self.database[self.selectedFeed.id]

    def entriesForFeed(self, feed, hideReadEntries):
        viewName = CouchDb.feedEntriesByFeed()
        if hideReadEntries:
            viewName = CouchDb.unreadFeedEntriesByFeed()
        return list(FeedEntry.view(self.database, viewName))

    def markFeedEntriesAsRead(self, indices):
        for index in indices:
            feedEntry = self.entriesForSelectedFeed()[index]
            feedEntry.markRead(self.database)

    def updateAllFeeds(self):
        # TODO: use a view instead of iterating all feeds
        allFeeds = Feed.all(self.database)
        for feed in allFeeds:
            if feed.needsUpdate():
                try:
                    FeedUpdater(self.database, self.preferences()).update(feed)
                except Exception as ex:
                    logging.getLogger("FeedUpdate").error("Exception during fetch: " + str(ex))

    def expireFeedEntries(self):
        expireDate = self._calculateExpireDate()
        logger = logging.getLogger("expiry")
        logger.info("expiring entries older than " + str(expireDate))
        for entry in FeedEntry.getReadFeedEntriesOlderThan(expireDate, self.database):
            del self.database[entry.id]