2009-06-16 03:08:55 +00:00
|
|
|
from django.db import models
|
2009-09-08 00:13:49 +00:00
|
|
|
from django.db import IntegrityError
|
2009-06-16 03:08:55 +00:00
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2010-01-04 04:49:59 +00:00
|
|
|
from django.core import serializers
|
2009-06-16 03:08:55 +00:00
|
|
|
from django.core.cache import cache
|
2010-04-05 02:42:43 -04:00
|
|
|
from utils import feedparser, object_manager, json
|
2009-06-16 03:08:55 +00:00
|
|
|
from utils.dateutil.parser import parse as dateutil_parse
|
2009-08-01 04:26:57 +00:00
|
|
|
from utils.feed_functions import encode, prints, mtime, levenshtein_distance
|
2009-06-16 03:08:55 +00:00
|
|
|
import time, datetime, random
|
|
|
|
from django.utils.http import urlquote
|
2009-07-28 02:27:27 +00:00
|
|
|
from django.utils.safestring import mark_safe
|
|
|
|
from utils.story_functions import format_story_link_date__short
|
|
|
|
from utils.story_functions import format_story_link_date__long
|
2009-12-18 20:47:44 +00:00
|
|
|
from utils.story_functions import pre_process_story
|
2010-01-27 16:28:57 -05:00
|
|
|
from utils.compressed_textfield import StoryField
|
2009-06-16 03:08:55 +00:00
|
|
|
from django.db.models import Q
|
2009-08-09 19:22:09 +00:00
|
|
|
import settings
|
2009-07-20 05:12:11 +00:00
|
|
|
import logging
|
2009-08-30 00:43:13 +00:00
|
|
|
import difflib
|
2010-04-19 12:09:04 -04:00
|
|
|
import datetime
|
2010-04-29 11:18:49 -04:00
|
|
|
import hashlib
|
2009-08-29 19:34:42 +00:00
|
|
|
from utils.diff import HTMLDiff
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
USER_AGENT = 'NewsBlur v1.0 - newsblur.com'
|
|
|
|
|
2009-08-20 02:43:01 +00:00
|
|
|
ENTRY_NEW, ENTRY_UPDATED, ENTRY_SAME, ENTRY_ERR = range(4)
|
2009-07-21 03:18:29 +00:00
|
|
|
|
2009-06-16 03:08:55 +00:00
|
|
|
class Feed(models.Model):
|
|
|
|
feed_address = models.URLField(max_length=255, verify_exists=True, unique=True)
|
2010-04-25 18:31:54 -04:00
|
|
|
feed_link = models.URLField(max_length=200, default="")
|
|
|
|
feed_title = models.CharField(max_length=255, default="")
|
|
|
|
feed_tagline = models.CharField(max_length=1024, default="")
|
2009-06-16 03:08:55 +00:00
|
|
|
active = models.BooleanField(default=True)
|
|
|
|
num_subscribers = models.IntegerField(default=0)
|
|
|
|
last_update = models.DateTimeField(auto_now=True, default=0)
|
|
|
|
min_to_decay = models.IntegerField(default=15)
|
|
|
|
days_to_trim = models.IntegerField(default=90)
|
|
|
|
creation = models.DateField(auto_now_add=True)
|
2010-04-13 19:35:36 -04:00
|
|
|
etag = models.CharField(max_length=50, blank=True, null=True)
|
2009-06-16 03:08:55 +00:00
|
|
|
last_modified = models.DateTimeField(null=True, blank=True)
|
2010-01-27 16:28:57 -05:00
|
|
|
page_data = StoryField(null=True, blank=True)
|
2010-04-19 12:09:04 -04:00
|
|
|
stories_per_month = models.IntegerField(default=0)
|
|
|
|
next_scheduled_update = models.DateTimeField(default=datetime.datetime.now)
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return self.feed_title
|
|
|
|
|
|
|
|
def last_updated(self):
|
|
|
|
return time.time() - time.mktime(self.last_update.timetuple())
|
|
|
|
|
|
|
|
def new_stories_since_date(self, date):
|
2010-01-21 13:12:29 -05:00
|
|
|
stories = Story.objects.filter(story_date__gte=date,
|
|
|
|
story_feed=self)
|
|
|
|
return stories
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
def add_feed(self, feed_address, feed_link, feed_title):
|
|
|
|
print locals()
|
|
|
|
|
2010-04-09 16:37:19 -04:00
|
|
|
def update(self, force=False, feed=None, single_threaded=False):
|
2009-08-29 19:34:42 +00:00
|
|
|
from utils import feed_fetcher
|
2009-08-14 01:54:22 +00:00
|
|
|
try:
|
|
|
|
self.feed_address = self.feed_address % {'NEWSBLUR_DIR': settings.NEWSBLUR_DIR}
|
|
|
|
except:
|
|
|
|
pass
|
2009-08-01 04:26:57 +00:00
|
|
|
|
2009-08-29 19:34:42 +00:00
|
|
|
options = {
|
2009-11-15 18:57:53 +00:00
|
|
|
'verbose': 2,
|
2010-04-09 16:37:19 -04:00
|
|
|
'timeout': 10,
|
|
|
|
'single_threaded': single_threaded,
|
2010-04-29 11:18:49 -04:00
|
|
|
'force': force,
|
2009-08-29 19:34:42 +00:00
|
|
|
}
|
|
|
|
disp = feed_fetcher.Dispatcher(options, 1)
|
2009-11-15 18:57:53 +00:00
|
|
|
disp.add_jobs([[self]])
|
|
|
|
disp.run_jobs()
|
2009-08-29 19:34:42 +00:00
|
|
|
disp.poll()
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
def add_update_stories(self, stories, existing_stories):
|
2009-08-20 02:43:01 +00:00
|
|
|
ret_values = {
|
|
|
|
ENTRY_NEW:0,
|
|
|
|
ENTRY_UPDATED:0,
|
|
|
|
ENTRY_SAME:0,
|
|
|
|
ENTRY_ERR:0
|
|
|
|
}
|
|
|
|
|
2009-06-16 03:08:55 +00:00
|
|
|
for story in stories:
|
2009-12-18 20:47:44 +00:00
|
|
|
story = pre_process_story(story)
|
2010-01-04 22:26:53 +00:00
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
if story.get('title'):
|
|
|
|
story_contents = story.get('content')
|
2010-01-04 22:26:53 +00:00
|
|
|
story_tags = self.get_tags(story)
|
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
if story_contents is not None:
|
|
|
|
story_content = story_contents[0]['value']
|
2009-06-16 03:08:55 +00:00
|
|
|
else:
|
2009-08-01 04:26:57 +00:00
|
|
|
story_content = story.get('summary')
|
2010-01-04 22:26:53 +00:00
|
|
|
|
2009-08-30 00:43:13 +00:00
|
|
|
existing_story, story_has_changed = self._exists_story(story, story_content, existing_stories)
|
2009-12-18 20:47:44 +00:00
|
|
|
story_author, _ = self._save_story_author(story.get('author'))
|
2009-08-01 04:26:57 +00:00
|
|
|
if existing_story is None:
|
|
|
|
pub_date = datetime.datetime.timetuple(story.get('published'))
|
2009-08-14 01:48:21 +00:00
|
|
|
# logging.debug('- New story: %s %s' % (pub_date, story.get('title')))
|
2009-12-18 20:47:44 +00:00
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
s = Story(story_feed = self,
|
|
|
|
story_date = story.get('published'),
|
|
|
|
story_title = story.get('title'),
|
|
|
|
story_content = story_content,
|
2009-12-18 20:47:44 +00:00
|
|
|
story_author = story_author,
|
2009-09-05 02:22:25 +00:00
|
|
|
story_permalink = story.get('link'),
|
2010-04-05 02:42:43 -04:00
|
|
|
story_guid = story.get('guid') or story.get('id') or story.get('link'),
|
|
|
|
story_tags = json.encode([t.name for t in story_tags])
|
2009-08-01 04:26:57 +00:00
|
|
|
)
|
|
|
|
try:
|
2009-08-20 02:43:01 +00:00
|
|
|
ret_values[ENTRY_NEW] += 1
|
2009-08-01 04:26:57 +00:00
|
|
|
s.save(force_insert=True)
|
2009-09-08 00:13:49 +00:00
|
|
|
except IntegrityError, e:
|
2009-08-20 02:43:01 +00:00
|
|
|
ret_values[ENTRY_ERR] += 1
|
2009-12-18 20:47:44 +00:00
|
|
|
print('Saving new story, IntegrityError: %s - %s: %s' % (self.feed_title, story.get('title'), e))
|
2010-01-04 22:26:53 +00:00
|
|
|
[s.tags.add(tcat) for tcat in story_tags]
|
2009-08-30 00:43:13 +00:00
|
|
|
elif existing_story and story_has_changed:
|
2009-08-01 04:26:57 +00:00
|
|
|
# update story
|
2010-01-27 16:28:57 -05:00
|
|
|
logging.debug('- Updated story in feed (%s - %s): %s / %s' % (self.feed_title, story.get('title'), len(existing_story.story_content), len(story_content)))
|
2009-08-01 04:26:57 +00:00
|
|
|
|
|
|
|
original_content = None
|
2010-01-27 16:28:57 -05:00
|
|
|
if existing_story.story_original_content:
|
|
|
|
original_content = existing_story.story_original_content
|
2009-08-01 04:26:57 +00:00
|
|
|
else:
|
2010-01-27 16:28:57 -05:00
|
|
|
original_content = existing_story.story_content
|
2010-01-27 18:08:07 -05:00
|
|
|
# print 'Type: %s %s' % (type(original_content), type(story_content))
|
|
|
|
diff = HTMLDiff(unicode(original_content), story_content)
|
2009-08-01 04:26:57 +00:00
|
|
|
# logging.debug("\t\tDiff: %s %s %s" % diff.getStats())
|
|
|
|
# logging.debug("\t\tDiff content: %s" % diff.getDiff())
|
2010-01-27 16:28:57 -05:00
|
|
|
if existing_story.story_title != story.get('title'):
|
|
|
|
# logging.debug('\tExisting title / New: : \n\t\t- %s\n\t\t- %s' % (existing_story.story_title, story.get('title')))
|
2009-08-14 01:48:21 +00:00
|
|
|
pass
|
2009-06-16 03:08:55 +00:00
|
|
|
|
2010-01-27 16:28:57 -05:00
|
|
|
s = Story(id = existing_story.id,
|
2009-08-01 04:26:57 +00:00
|
|
|
story_feed = self,
|
|
|
|
story_date = story.get('published'),
|
|
|
|
story_title = story.get('title'),
|
|
|
|
story_content = diff.getDiff(),
|
|
|
|
story_original_content = original_content,
|
2009-12-18 20:47:44 +00:00
|
|
|
story_author = story_author,
|
2009-09-05 02:22:25 +00:00
|
|
|
story_permalink = story.get('link'),
|
2010-04-05 02:42:43 -04:00
|
|
|
story_guid = story.get('guid') or story.get('id') or story.get('link'),
|
|
|
|
story_tags = json.encode([t.name for t in story_tags])
|
2009-08-01 04:26:57 +00:00
|
|
|
)
|
2010-01-04 22:26:53 +00:00
|
|
|
s.tags.clear()
|
|
|
|
[s.tags.add(tcat) for tcat in story_tags]
|
2009-08-01 04:26:57 +00:00
|
|
|
try:
|
2009-08-20 02:43:01 +00:00
|
|
|
ret_values[ENTRY_UPDATED] += 1
|
2009-08-01 04:26:57 +00:00
|
|
|
s.save(force_update=True)
|
2009-09-08 00:13:49 +00:00
|
|
|
except IntegrityError, e:
|
|
|
|
ret_values[ENTRY_ERR] += 1
|
2009-12-18 20:47:44 +00:00
|
|
|
print('Saving updated story, IntegrityError: %s - %s' % (self.feed_title, story.get('title')))
|
2009-08-20 02:43:01 +00:00
|
|
|
else:
|
|
|
|
ret_values[ENTRY_SAME] += 1
|
2009-08-01 04:26:57 +00:00
|
|
|
# logging.debug("Unchanged story: %s " % story.get('title'))
|
2009-06-16 03:08:55 +00:00
|
|
|
|
2009-08-20 02:43:01 +00:00
|
|
|
return ret_values
|
2009-06-16 03:08:55 +00:00
|
|
|
|
2009-12-18 20:47:44 +00:00
|
|
|
def _save_story_author(self, author):
|
|
|
|
author, created = StoryAuthor.objects.get_or_create(feed=self, author_name=author)
|
|
|
|
return author, created
|
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
def trim_feed(self):
|
2010-01-26 19:59:43 -05:00
|
|
|
from apps.reader.models import UserStory
|
|
|
|
stories_deleted_count = 0
|
2010-01-26 20:27:11 -05:00
|
|
|
user_stories_count = 0
|
2010-01-26 19:59:43 -05:00
|
|
|
stories = Story.objects.filter(story_feed=self).order_by('-story_date')
|
2010-01-26 20:02:36 -05:00
|
|
|
print 'Found %s stories in %s. Trimming...' % (stories.count(), self)
|
2010-02-12 19:30:26 -05:00
|
|
|
if stories.count() > 1000:
|
2010-02-12 19:34:32 -05:00
|
|
|
old_story = stories[1000]
|
2010-02-12 19:34:03 -05:00
|
|
|
user_stories = UserStory.objects.filter(feed=self,
|
2010-02-12 19:33:18 -05:00
|
|
|
read_date__lte=old_story.story_date)
|
|
|
|
user_stories_count = user_stories.count()
|
|
|
|
user_stories.delete()
|
2010-02-12 19:30:26 -05:00
|
|
|
old_stories = Story.objects.filter(story_feed=self,
|
|
|
|
story_date__lte=old_story.story_date)
|
2010-02-12 19:33:18 -05:00
|
|
|
stories_deleted_count = old_stories.count()
|
2010-02-12 19:30:26 -05:00
|
|
|
old_stories.delete()
|
2009-08-01 04:26:57 +00:00
|
|
|
|
2010-01-26 19:59:43 -05:00
|
|
|
if stories_deleted_count:
|
|
|
|
print "Trimming %s stories from %s. %s user stories." % (
|
|
|
|
stories_deleted_count,
|
|
|
|
self,
|
|
|
|
user_stories_count)
|
|
|
|
|
2009-07-28 02:27:27 +00:00
|
|
|
def get_stories(self, offset=0, limit=25):
|
2010-01-04 04:49:59 +00:00
|
|
|
stories = cache.get('feed_stories:%s-%s-%s' % (self.id, offset, limit), [])
|
2010-01-21 13:12:29 -05:00
|
|
|
|
2010-01-04 04:49:59 +00:00
|
|
|
if not stories:
|
2010-01-21 13:12:29 -05:00
|
|
|
stories_db = Story.objects.filter(story_feed=self)\
|
|
|
|
.select_related('story_author')[offset:offset+limit]
|
|
|
|
stories = self.format_stories(stories_db)
|
2010-01-26 20:39:11 -05:00
|
|
|
cache.set('feed_stories:%s-%s-%s' % (self.id, offset, limit), stories, 600)
|
2009-07-28 02:27:27 +00:00
|
|
|
|
|
|
|
return stories
|
|
|
|
|
2010-01-21 13:12:29 -05:00
|
|
|
def format_stories(self, stories_db):
|
|
|
|
stories = []
|
2010-04-05 02:42:43 -04:00
|
|
|
# from django.db import connection
|
|
|
|
# print "Formatting Stories: %s" % stories_db.count()
|
2010-01-21 13:12:29 -05:00
|
|
|
for story_db in stories_db:
|
2010-02-17 03:22:45 -05:00
|
|
|
story = {}
|
2010-04-05 02:55:18 -04:00
|
|
|
# story_tags = story_db.tags.all()
|
2010-04-05 03:20:44 -04:00
|
|
|
story['story_tags'] = (story_db.story_tags and json.decode(story_db.story_tags)) or []
|
2010-02-17 03:22:45 -05:00
|
|
|
story['short_parsed_date'] = format_story_link_date__short(story_db.story_date)
|
|
|
|
story['long_parsed_date'] = format_story_link_date__long(story_db.story_date)
|
|
|
|
story['story_date'] = story_db.story_date
|
2010-01-21 13:12:29 -05:00
|
|
|
story['story_authors'] = story_db.story_author.author_name
|
2010-02-17 03:22:45 -05:00
|
|
|
story['story_title'] = story_db.story_title
|
|
|
|
story['story_content'] = story_db.story_content
|
|
|
|
story['story_permalink'] = story_db.story_permalink
|
2010-04-05 03:20:44 -04:00
|
|
|
story['story_feed_id'] = self.pk
|
2010-02-17 03:22:45 -05:00
|
|
|
story['id'] = story_db.id
|
|
|
|
|
2010-01-21 13:12:29 -05:00
|
|
|
stories.append(story)
|
|
|
|
|
|
|
|
return stories
|
|
|
|
|
2010-01-04 22:26:53 +00:00
|
|
|
def get_tags(self, entry):
|
|
|
|
fcat = []
|
|
|
|
if entry.has_key('tags'):
|
|
|
|
for tcat in entry.tags:
|
|
|
|
if tcat.label != None:
|
|
|
|
term = tcat.label
|
|
|
|
else:
|
|
|
|
term = tcat.term
|
|
|
|
qcat = term.strip()
|
|
|
|
if ',' in qcat or '/' in qcat:
|
|
|
|
qcat = qcat.replace(',', '/').split('/')
|
|
|
|
else:
|
|
|
|
qcat = [qcat]
|
|
|
|
for zcat in qcat:
|
|
|
|
tagname = zcat.lower()
|
|
|
|
while ' ' in tagname:
|
|
|
|
tagname = tagname.replace(' ', ' ')
|
|
|
|
tagname = tagname.strip()
|
|
|
|
if not tagname or tagname == ' ':
|
|
|
|
continue
|
|
|
|
if not Tag.objects.filter(name=tagname, feed=self):
|
|
|
|
cobj = Tag(name=tagname, feed=self)
|
|
|
|
cobj.save()
|
|
|
|
fcat.append(Tag.objects.get(name=tagname, feed=self))
|
|
|
|
return fcat
|
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
def _exists_story(self, story=None, story_content=None, existing_stories=None):
|
2009-08-30 00:43:13 +00:00
|
|
|
story_in_system = None
|
|
|
|
story_has_changed = False
|
2009-08-01 04:26:57 +00:00
|
|
|
story_pub_date = story.get('published')
|
2010-01-28 13:28:27 -05:00
|
|
|
story_published_now = story.get('published_now', False)
|
2009-08-01 04:26:57 +00:00
|
|
|
start_date = story_pub_date - datetime.timedelta(hours=8)
|
|
|
|
end_date = story_pub_date + datetime.timedelta(hours=8)
|
2009-08-30 00:43:13 +00:00
|
|
|
|
2009-08-01 04:26:57 +00:00
|
|
|
for existing_story in existing_stories:
|
2009-08-30 00:43:13 +00:00
|
|
|
content_ratio = 0
|
2010-01-28 13:28:27 -05:00
|
|
|
# print 'Story pub date: %s %s' % (story_published_now, story_pub_date)
|
|
|
|
if story_published_now or\
|
|
|
|
(story_pub_date > start_date and story_pub_date < end_date):
|
|
|
|
if story.get('guid') and story.get('guid') == existing_story.story_guid:
|
2009-09-05 02:22:25 +00:00
|
|
|
story_in_system = existing_story
|
2010-01-27 16:28:57 -05:00
|
|
|
elif story.get('link') and story.get('link') == existing_story.story_permalink:
|
2009-08-30 00:43:13 +00:00
|
|
|
story_in_system = existing_story
|
|
|
|
|
2009-09-07 01:56:52 +00:00
|
|
|
# import pdb
|
|
|
|
# pdb.set_trace()
|
2009-09-10 03:33:05 +00:00
|
|
|
|
2009-08-30 00:43:13 +00:00
|
|
|
# Title distance + content distance, checking if story changed
|
2009-08-01 04:26:57 +00:00
|
|
|
story_title_difference = levenshtein_distance(story.get('title'),
|
2010-01-27 16:28:57 -05:00
|
|
|
existing_story.story_title)
|
|
|
|
seq = difflib.SequenceMatcher(None, story_content, existing_story.story_content)
|
2009-08-30 00:43:13 +00:00
|
|
|
|
2010-04-29 11:18:49 -04:00
|
|
|
if seq and seq.real_quick_ratio() > .9 and seq.quick_ratio() > .95:
|
2009-08-30 00:43:13 +00:00
|
|
|
content_ratio = seq.ratio()
|
|
|
|
|
|
|
|
if story_title_difference > 0 and story_title_difference < 5 and content_ratio > .98:
|
|
|
|
story_in_system = existing_story
|
|
|
|
if story_title_difference > 0 or content_ratio < 1.0:
|
2010-01-27 16:28:57 -05:00
|
|
|
# print "Title difference - %s/%s (%s): %s" % (story.get('title'), existing_story.story_title, story_title_difference, content_ratio)
|
2009-08-30 00:43:13 +00:00
|
|
|
story_has_changed = True
|
|
|
|
break
|
|
|
|
|
|
|
|
# More restrictive content distance, still no story match
|
2009-09-07 01:56:52 +00:00
|
|
|
if not story_in_system and content_ratio > .98:
|
2010-01-27 16:28:57 -05:00
|
|
|
# print "Content difference - %s/%s (%s): %s" % (story.get('title'), existing_story.story_title, story_title_difference, content_ratio)
|
2009-08-30 00:43:13 +00:00
|
|
|
story_in_system = existing_story
|
|
|
|
story_has_changed = True
|
|
|
|
break
|
2009-08-01 04:26:57 +00:00
|
|
|
|
2009-08-30 00:43:13 +00:00
|
|
|
if story_in_system:
|
2010-01-27 16:28:57 -05:00
|
|
|
if story_content != existing_story.story_content:
|
2009-08-30 00:43:13 +00:00
|
|
|
story_has_changed = True
|
2009-08-01 04:26:57 +00:00
|
|
|
break
|
2010-01-28 13:28:27 -05:00
|
|
|
|
2010-02-02 18:01:02 -05:00
|
|
|
# if story_has_changed or not story_in_system:
|
|
|
|
# print 'New/updated story: %s' % (story),
|
2009-08-30 00:43:13 +00:00
|
|
|
return story_in_system, story_has_changed
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
db_table="feeds"
|
|
|
|
ordering=["feed_title"]
|
|
|
|
|
|
|
|
class Tag(models.Model):
|
2010-01-04 22:26:53 +00:00
|
|
|
feed = models.ForeignKey(Feed)
|
|
|
|
name = models.CharField(max_length=255)
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
def __unicode__(self):
|
2010-01-04 22:26:53 +00:00
|
|
|
return '%s - %s' % (self.feed, self.name)
|
2009-06-16 03:08:55 +00:00
|
|
|
|
|
|
|
def save(self):
|
|
|
|
super(Tag, self).save()
|
|
|
|
|
2009-12-18 20:47:44 +00:00
|
|
|
class StoryAuthor(models.Model):
|
|
|
|
feed = models.ForeignKey(Feed)
|
|
|
|
author_name = models.CharField(max_length=255, null=True, blank=True)
|
|
|
|
|
2009-12-18 21:59:14 +00:00
|
|
|
def __unicode__(self):
|
|
|
|
return '%s - %s' % (self.feed, self.author_name)
|
|
|
|
|
2009-06-16 03:08:55 +00:00
|
|
|
class Story(models.Model):
|
|
|
|
'''A feed item'''
|
2010-04-09 16:10:23 -04:00
|
|
|
story_feed = models.ForeignKey(Feed, related_name="stories")
|
2009-06-16 03:08:55 +00:00
|
|
|
story_date = models.DateTimeField()
|
|
|
|
story_title = models.CharField(max_length=255)
|
2010-01-27 16:28:57 -05:00
|
|
|
story_content = StoryField(null=True, blank=True)
|
|
|
|
story_original_content = StoryField(null=True, blank=True)
|
2009-06-16 03:08:55 +00:00
|
|
|
story_content_type = models.CharField(max_length=255, null=True,
|
|
|
|
blank=True)
|
2009-12-18 20:47:44 +00:00
|
|
|
story_author = models.ForeignKey(StoryAuthor)
|
2009-06-16 03:08:55 +00:00
|
|
|
story_permalink = models.CharField(max_length=1000)
|
2009-09-05 02:22:25 +00:00
|
|
|
story_guid = models.CharField(max_length=1000)
|
2010-04-29 11:18:49 -04:00
|
|
|
story_guid_hash = models.CharField(max_length=40)
|
2009-06-16 03:08:55 +00:00
|
|
|
story_past_trim_date = models.BooleanField(default=False)
|
2010-04-05 02:42:43 -04:00
|
|
|
story_tags = models.CharField(max_length=1000)
|
2009-06-16 03:08:55 +00:00
|
|
|
tags = models.ManyToManyField(Tag)
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return self.story_title
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
verbose_name_plural = "stories"
|
|
|
|
verbose_name = "story"
|
|
|
|
db_table="stories"
|
2009-07-18 23:39:16 +00:00
|
|
|
ordering=["-story_date"]
|
2009-08-14 02:32:30 +00:00
|
|
|
|
2010-04-29 11:18:49 -04:00
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
if not self.story_guid_hash and self.story_guid:
|
|
|
|
self.story_guid_hash = hashlib.md5(self.story_guid).hexdigest()
|
|
|
|
super(Story, self).save(*args, **kwargs)
|
|
|
|
|
2010-04-23 21:19:19 -04:00
|
|
|
class FeedUpdateHistory(models.Model):
|
|
|
|
fetch_date = models.DateTimeField(default=datetime.datetime.now)
|
|
|
|
number_of_feeds = models.IntegerField()
|
|
|
|
seconds_taken = models.IntegerField()
|
2010-04-25 16:11:04 -04:00
|
|
|
average_per_feed = models.DecimalField(decimal_places=1, max_digits=4)
|
2010-04-23 21:19:19 -04:00
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return "[%s] %s feeds: %s seconds" % (
|
|
|
|
fetch_date.strftime('%F %d'),
|
|
|
|
self.number_of_feeds,
|
|
|
|
self.seconds_taken,
|
|
|
|
)
|
2010-04-25 16:11:04 -04:00
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
self.average_per_feed = str(self.seconds_taken / float(max(1.0,self.number_of_feeds)))
|
|
|
|
super(FeedUpdateHistory, self).save(*args, **kwargs)
|
2010-04-23 21:19:19 -04:00
|
|
|
|