Permalink
Browse files

Statistics graph.

  • Loading branch information...
1 parent cb125b8 commit 909339381a8e92295e86b74dc9d9310d608347e8 @samuelclay committed Apr 15, 2011
View
3 apps/profile/middleware.py
@@ -5,8 +5,7 @@
class LastSeenMiddleware(object):
def process_response(self, request, response):
- if (request.path == '/'
- and not request.is_ajax()
+ if ((request.path in ('/', '/reader/refresh_feeds'))
and hasattr(request, 'user')
and request.user.is_authenticated()):
hour_ago = datetime.datetime.utcnow() - datetime.timedelta(minutes=60)
View
3 apps/reader/views.py
@@ -23,6 +23,7 @@
from apps.reader.models import UserSubscription, UserSubscriptionFolders, MUserStory, Feature
from apps.reader.forms import SignupForm, LoginForm, FeatureForm
from apps.rss_feeds.models import FeedIcon
+from apps.statistics.models import MStatistics
try:
from apps.rss_feeds.models import Feed, MFeedPage, DuplicateFeed, MStory, MStarredStory, FeedLoadtime
except:
@@ -70,6 +71,7 @@ def index(request):
recommended_feeds = RecommendedFeed.objects.filter(is_public=True, approved_date__lte=now).select_related('feed')
# recommended_feed_feedback = RecommendedFeedUserFeedback.objects.filter(recommendation=recommended_feed)
+ statistics = MStatistics.all()
howitworks_page = 0 # random.randint(0, 5)
return render_to_response('reader/feeds.xhtml', {
'user_profile': user.profile,
@@ -84,6 +86,7 @@ def index(request):
'train_count': active_count - train_count,
'account_images': range(1, 4),
'recommended_feeds': recommended_feeds,
+ 'statistics': statistics,
# 'recommended_feed_feedback': recommended_feed_feedback,
}, context_instance=RequestContext(request))
View
9 apps/rss_feeds/models.py
@@ -231,7 +231,12 @@ def save_feed_history(self, status_code, message, exception=None):
message=message,
exception=exception,
fetch_date=datetime.datetime.utcnow()).save()
- old_fetch_histories = MFeedFetchHistory.objects(feed_id=self.pk).order_by('-fetch_date')[5:]
+ day_ago = datetime.datetime.now() - datetime.timedelta(hours=24)
+ new_fetch_histories = MFeedFetchHistory.objects(feed_id=self.pk, fetch_date__gte=day_ago)
+ if new_fetch_histories.count() < 5:
+ old_fetch_histories = MFeedFetchHistory.objects(feed_id=self.pk)[5:]
+ else:
+ old_fetch_histories = MFeedFetchHistory.objects(feed_id=self.pk, fetch_date__lte=day_ago)
for history in old_fetch_histories:
history.delete()
if status_code not in (200, 304):
@@ -1018,6 +1023,7 @@ class MFeedFetchHistory(mongo.Document):
meta = {
'collection': 'feed_fetch_history',
'allow_inheritance': False,
+ 'ordering': ['-fetch_date'],
'indexes': [('fetch_date', 'status_code'), ('feed_id', 'status_code'), ('feed_id', 'fetch_date')],
}
@@ -1050,6 +1056,7 @@ class MPageFetchHistory(mongo.Document):
meta = {
'collection': 'page_fetch_history',
'allow_inheritance': False,
+ 'ordering': ['-fetch_date'],
'indexes': [('fetch_date', 'status_code'), ('feed_id', 'status_code'), ('feed_id', 'fetch_date')],
}
View
0 apps/statistics/__init__.py
No changes.
View
0 apps/statistics/management/__init__.py
No changes.
View
0 apps/statistics/management/commands/__init__.py
No changes.
View
10 apps/statistics/management/commands/collect_stats.py
@@ -0,0 +1,10 @@
+from optparse import make_option
+from django.core.management.base import BaseCommand
+from apps.statistics.models import MStatistics
+
+class Command(BaseCommand):
+ option_list = BaseCommand.option_list + (
+ )
+
+ def handle(self, *args, **options):
+ MStatistics.collect_statistics()
View
33 apps/statistics/models.py
@@ -0,0 +1,33 @@
+import datetime
+import mongoengine as mongo
+from apps.rss_feeds.models import MFeedFetchHistory
+from apps.profile.models import Profile
+
+class MStatistics(mongo.Document):
+ key = mongo.StringField(unique=True)
+ value = mongo.IntField(default=0)
+
+ meta = {
+ 'collection': 'statistics',
+ 'allow_inheritance': False,
+ 'indexes': ['key'],
+ }
+
+ def __unicode__(self):
+ return "%s: %s" % (self.key, self.value)
+
+ @classmethod
+ def all(cls):
+ return dict([(stat.key, stat.value) for stat in cls.objects.all()])
+
+ @classmethod
+ def collect_statistics(cls):
+ last_day = datetime.datetime.now() - datetime.timedelta(hours=24)
+ feeds_fetched = MFeedFetchHistory.objects(fetch_date__gte=last_day).count()
+ cls.objects(key='feeds_fetched').update_one(upsert=True, key='feeds_fetched', value=feeds_fetched)
+
+ premium_users = Profile.objects.filter(last_seen_on__gte=last_day, is_premium=True).count()
+ cls.objects(key='premium_users').update_one(upsert=True, key='premium_users', value=premium_users)
+
+ standard_users = Profile.objects.filter(last_seen_on__gte=last_day, is_premium=False).count()
+ cls.objects(key='standard_users').update_one(upsert=True, key='standard_users', value=standard_users)
View
23 apps/statistics/tests.py
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
View
1 apps/statistics/views.py
@@ -0,0 +1 @@
+# Create your views here.
View
8 config/staging.conf
@@ -7,7 +7,7 @@ server {
client_max_body_size 4G;
server_name dev.newsblur.com;
- if (-f /home/conesus/staging/media/maintenance.html) {
+ if (-f /home/sclay/staging/media/maintenance.html) {
rewrite ^(.*) http://www.newsblur.com;
break;
}
@@ -17,17 +17,17 @@ server {
}
location /media/ {
expires max;
- root /home/conesus/staging;
+ root /home/sclay/staging;
}
location /favicon.ico {
- alias /home/conesus/staging/media/img/favicon.png;
+ alias /home/sclay/staging/media/img/favicon.png;
expires max;
access_log off;
}
location ^~ /crossdomain.xml {
expires max;
- alias /home/conesus/staging/media/crossdomain.xml;
+ alias /home/sclay/staging/media/crossdomain.xml;
types {
text/x-cross-domain-policy xml;
}
View
12 fabfile.py
@@ -62,14 +62,14 @@ def deploy_full():
def staging():
with cd('~/staging'):
run('git pull')
- run('kill -HUP `cat /var/run/gunicorn/gunicorn_staging.pid`')
+ run('kill -HUP `cat logs/gunicorn.pid`')
@roles('web')
def staging_full():
with cd('~/staging'):
run('git pull')
run('./manage.py migrate')
- run('kill -HUP `cat /var/run/gunicorn/gunicorn_staging.pid`')
+ run('kill -HUP `cat logs/gunicorn.pid`')
@roles('task')
def celery():
@@ -295,6 +295,14 @@ def update_gunicorn():
run('git pull')
sudo('python setup.py develop')
+@roles('web')
+def setup_staging():
+ run('git clone https://github.com/samuelclay/NewsBlur.git staging')
+ with cd('~/staging'):
+ run('cp ../newsblur/local_settings.py local_settings.py')
+ run('mkdir -p logs')
+ run('touch logs/newsblur.log')
+
# ==============
# = Setup - DB =
# ==============
View
3 media/css/reader.css
@@ -3573,13 +3573,14 @@ background: transparent;
.NB-graph-value .NB-graph-label {
width: 20px;
height: 20px;
+ font-size: 10px;
text-align: center;
position: absolute;
bottom: -25px;
left: -8px;
display: none;
padding: 3px 0 0 0;
- color: #808080;
+ color: #A0A0A0;
text-shadow: 1px 1px 0 #F0F0F0;
background: transparent url('../img/reader/graph_arrow_up.png') no-repeat 8px 0;
}
View
1 settings.py
@@ -252,6 +252,7 @@
'apps.feed_import',
'apps.profile',
'apps.recommendations',
+ 'apps.statistics',
'south',
'utils',
'vendor',
View
6 templates/reader/feeds.xhtml
@@ -313,15 +313,15 @@ $(document).ready(function() {
</h3>
<div class="NB-module-stats-count">
- <div class="NB-module-stats-count-number">38</div>
+ <div class="NB-module-stats-count-number">{{ statistics.premium_users }}</div>
<div class="NB-module-stats-count-description">Premium Users</div>
</div>
<div class="NB-module-stats-count">
- <div class="NB-module-stats-count-number">338</div>
+ <div class="NB-module-stats-count-number">{{ statistics.standard_users }}</div>
<div class="NB-module-stats-count-description">Standard Users</div>
</div>
<div class="NB-module-stats-count">
- <div class="NB-module-stats-count-number">94,510</div>
+ <div class="NB-module-stats-count-number">{{ statistics.feeds_fetched|commify }}</div>
<div class="NB-module-stats-count-description">Feeds fetched</div>
</div>
View
46 utils/templatetags/utils_tags.py
@@ -9,7 +9,7 @@ def current_domain():
@register.filter
def get_range( value ):
- """
+ """
Filter - returns a list containing range made from given value
Usage (in template):
@@ -25,5 +25,45 @@ def get_range( value ):
</ul>
Instead of 3 one may use the variable set in the views
- """
- return range( value )
+ """
+ return range( value )
+
+@register.filter
+def commify(n):
+ """
+ Add commas to an integer n.
+ >>> commify(1)
+ '1'
+ >>> commify(123)
+ '123'
+ >>> commify(1234)
+ '1,234'
+ >>> commify(1234567890)
+ '1,234,567,890'
+ >>> commify(123.0)
+ '123.0'
+ >>> commify(1234.5)
+ '1,234.5'
+ >>> commify(1234.56789)
+ '1,234.56789'
+ >>> commify('%.2f' % 1234.5)
+ '1,234.50'
+ >>> commify(None)
+
+ """
+ if n is None: return None
+ n = str(n)
+ if '.' in n:
+ dollars, cents = n.split('.')
+ else:
+ dollars, cents = n, None
+
+ r = []
+ for i, c in enumerate(str(dollars)[::-1]):
+ if i and (not (i % 3)):
+ r.insert(0, ',')
+ r.insert(0, c)
+ out = ''.join(r)
+ if cents:
+ out += '.' + cents
+ return out

0 comments on commit 9093393

Please sign in to comment.