Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add the user stats api endpoint. #328

Merged
merged 1 commit into from

2 participants

@mitechie
Owner
  • Add docs for the new endpoint
  • Add the api endpoint to return user's bookmark counts

This is a cleaned up merge from Sambuddha Basu. All credit to him and his
work.

@sammyshj sammyshj Add the user stats api endpoint.
- Add docs for the new endpoint
- Add the api endpoint to return user's bookmark counts

This is a cleaned up merge from Sambuddha Basu. All credit to him and his
work.
a24ec64
@mitechie mitechie merged commit a24ec64 into develop
@mitechie mitechie deleted the add-stats-api branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 5, 2014
  1. @sammyshj @mitechie

    Add the user stats api endpoint.

    sammyshj authored mitechie committed
    - Add docs for the new endpoint
    - Add the api endpoint to return user's bookmark counts
    
    This is a cleaned up merge from Sambuddha Basu. All credit to him and his
    work.
This page is out of date. Refresh to see the latest.
View
46 bookie/models/stats.py
@@ -19,7 +19,11 @@
# 23 run xzy users.
"""
-from datetime import datetime
+from calendar import monthrange
+from datetime import (
+ datetime,
+ timedelta,
+)
from sqlalchemy import Column
from sqlalchemy import DateTime
@@ -38,6 +42,7 @@
UNIQUE_CT = u'unique_bookmarks'
TAG_CT = u'total_tags'
USER_CT = u'user_bookmarks_{0}'
+STATS_WINDOW = 30
class StatBookmarkMgr(object):
@@ -58,6 +63,18 @@ def get_stat(start, end, *stats):
return qry.all()
@staticmethod
+ def get_user_bmark_count(username, start_date, end_date):
+ """Fetch the bookmark count for the user from the stats table"""
+ qry = (StatBookmark.query.
+ filter(StatBookmark.attrib == USER_CT.format(username)).
+ filter(StatBookmark.tstamp >= start_date).
+ filter(StatBookmark.tstamp <= end_date))
+
+ # Order the result by their timestamp.
+ qry = qry.order_by(StatBookmark.tstamp)
+ return qry.all()
+
+ @staticmethod
def count_unique_bookmarks():
"""Count the unique number of bookmarks in the system"""
total = BmarkMgr.count(distinct=True)
@@ -95,6 +112,32 @@ def count_user_bookmarks(username):
)
DBSession.add(stat)
+ @staticmethod
+ def count_user_bmarks(username, start_date=None, end_date=None):
+ """Get a list of user bookmark count"""
+ if start_date:
+ start_date = datetime.strptime(start_date, '%Y-%m-%d %H:%M:%S')
+ if end_date:
+ end_date = datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S')
+ if not start_date:
+ if not end_date:
+ # If both start_date and end_date are None,
+ # end_date will be the current date
+ end_date = datetime.utcnow()
+ # Otherwise if there's no start_date but we have an end_date,
+ # assume that the user wants the STATS_WINDOW worth of stats.
+ start_date = end_date - timedelta(days=STATS_WINDOW)
+ elif start_date and not end_date:
+ if start_date.day == 1:
+ # If the starting day is 1, stats of the month is returned
+ days = monthrange(start_date.year, start_date.day)[1] - 2
+ end_date = start_date + timedelta(days=days)
+ else:
+ end_date = start_date + timedelta(days=STATS_WINDOW)
+ return [StatBookmarkMgr.get_user_bmark_count(username,
+ start_date, end_date),
+ start_date, end_date]
+
class StatBookmark(Base):
"""First stats we track are the counts of things.
@@ -110,3 +153,4 @@ class StatBookmark(Base):
def __init__(self, **kwargs):
self.attrib = kwargs.get('attrib', 'unknown')
self.data = kwargs.get('data', 0)
+ self.tstamp = kwargs.get('tstamp', datetime.utcnow())
View
2  bookie/routes.py
@@ -135,6 +135,8 @@ def build_routes(config):
config.add_route('api_bmarks_tags', 'api/v1/bmarks/*tags')
config.add_route('api_bmarks_user', 'api/v1/{username}/bmarks')
config.add_route('api_bmarks_user_tags', 'api/v1/{username}/bmarks/*tags')
+ config.add_route('api_count_bmarks_user',
+ 'api/v1/{username}/stats/bmarkcount')
config.add_route('api_bmarks_popular', 'api/v1/bmarks/popular')
config.add_route('api_bmarks_popular_user',
View
17 bookie/tests/factory.py
@@ -1,4 +1,5 @@
"""Provide tools for generating objects for testing purposes."""
+from datetime import datetime
from random import randint
import random
import string
@@ -8,6 +9,10 @@
from bookie.models import Tag
from bookie.models.applog import AppLog
from bookie.models.auth import User
+from bookie.models.stats import (
+ StatBookmark,
+ USER_CT,
+)
def random_int(max=1000):
@@ -76,6 +81,18 @@ def make_bookmark(user=None):
return bmark
+def make_user_bookmark_count(username, data, tstamp=None):
+ """Generate a fake user bookmark count for testing use"""
+ if tstamp is None:
+ tstamp = datetime.utcnow()
+ bmark_count = StatBookmark(tstamp=tstamp,
+ attrib=USER_CT.format(username),
+ data=data)
+ DBSession.add(bmark_count)
+ DBSession.flush()
+ return [bmark_count.attrib, bmark_count.data, bmark_count.tstamp]
+
+
def make_user(username=None):
"""Generate a fake user to test against."""
user = User()
View
128 bookie/tests/test_api/test_base_api.py
@@ -12,6 +12,12 @@
from bookie.models import DBSession
from bookie.tests import BOOKIE_TEST_INI
from bookie.tests import empty_db
+from bookie.tests import factory
+
+from datetime import (
+ datetime,
+ timedelta,
+)
GOOGLE_HASH = u'aa2239c17609b2'
BMARKUS_HASH = u'c5c21717c99797'
@@ -101,6 +107,23 @@ def _get_good_request(self, content=False, second_bmark=False):
tasks.reindex_fulltext_allbookmarks(sync=True)
return res
+ def _setup_user_bookmark_count(self):
+ """Fake user bookmark counts are inserted into the database"""
+ test_date_1 = datetime(2013, 11, 25, 3, 3, 3)
+ stat1 = factory.make_user_bookmark_count(username=u'admin',
+ data=20,
+ tstamp=test_date_1)
+ test_date_2 = datetime(2013, 11, 15, 4, 4, 4)
+ stat2 = factory.make_user_bookmark_count(username=u'admin',
+ data=30,
+ tstamp=test_date_2)
+ test_date_3 = datetime(2013, 12, 28, 5, 5, 5)
+ stat3 = factory.make_user_bookmark_count(username=u'admin',
+ data=15,
+ tstamp=test_date_3)
+ transaction.commit()
+ return [stat1, stat2, stat3]
+
def test_add_bookmark(self):
"""We should be able to add a new bookmark to the system"""
# we need to know what the current admin's api key is so we can try to
@@ -451,6 +474,111 @@ def test_bookmark_tag_complete(self):
"Should not have python as a tag completion: " + res.body)
self._check_cors_headers(res)
+ def test_start_defined_end(self):
+ """Test getting a user's bookmark count over a period of time when
+ only start_date is defined and end_date is None"""
+ test_dates = self._setup_user_bookmark_count()
+ test_start_date = datetime(2013, 11, 16, 6, 6, 6)
+ res = self.testapp.get(u'/api/v1/admin/stats/bmarkcount',
+ params={u'api_key': API_KEY,
+ u'start_date': test_start_date},
+ status=200)
+ data = json.loads(res.body)
+ count = data['count'][0]
+ self.assertEqual(
+ count['attrib'], test_dates[0][0])
+ self.assertEqual(
+ count['data'], test_dates[0][1])
+ self.assertEqual(
+ count['tstamp'], str(test_dates[0][2]))
+ # Test start_date and end_date.
+ self.assertEqual(
+ data['start_date'], str(test_start_date))
+ self.assertEqual(
+ data['end_date'], str(test_start_date + timedelta(days=30)))
+
+ def test_start_defined_end_defined(self):
+ """Test getting a user's bookmark count over a period of time when both
+ start_date and end_date are defined"""
+ test_dates = self._setup_user_bookmark_count()
+ test_start_date = datetime(2013, 11, 14, 7, 7, 7)
+ test_end_date = datetime(2013, 11, 16, 7, 7, 7)
+ res = self.testapp.get(u'/api/v1/admin/stats/bmarkcount',
+ params={u'api_key': API_KEY,
+ u'start_date': test_start_date,
+ u'end_date': test_end_date},
+ status=200)
+ data = json.loads(res.body)
+ count = data['count'][0]
+ self.assertEqual(
+ count['attrib'], test_dates[1][0])
+ self.assertEqual(
+ count['data'], test_dates[1][1])
+ self.assertEqual(
+ count['tstamp'], str(test_dates[1][2]))
+ # Test start_date and end_date.
+ self.assertEqual(
+ data['start_date'], str(test_start_date))
+ self.assertEqual(
+ data['end_date'], str(test_end_date))
+
+ def test_start_end_defined(self):
+ """Test getting a user's bookmark count over a period of time when
+ start_date is None and end_date is defined"""
+ test_dates = self._setup_user_bookmark_count()
+ test_end_date = datetime(2013, 12, 29, 8, 8, 8)
+ res = self.testapp.get(u'/api/v1/admin/stats/bmarkcount',
+ params={u'api_key': API_KEY,
+ u'end_date': test_end_date},
+ status=200)
+ data = json.loads(res.body)
+ count = data['count'][0]
+ self.assertEqual(
+ count['attrib'], test_dates[2][0])
+ self.assertEqual(
+ count['data'], test_dates[2][1])
+ self.assertEqual(
+ count['tstamp'], str(test_dates[2][2]))
+ # Test start_date and end_date.
+ self.assertEqual(
+ data['start_date'], str(test_end_date - timedelta(days=30)))
+ self.assertEqual(
+ data['end_date'], str(test_end_date))
+
+ def test_start_of_month(self):
+ """Test getting a user's bookmark count when start_date is the
+ first day of the month"""
+ test_dates = self._setup_user_bookmark_count()
+ test_start_date = datetime(2013, 11, 1, 9, 9, 9)
+ res = self.testapp.get(u'/api/v1/admin/stats/bmarkcount',
+ params={u'api_key': API_KEY,
+ u'start_date': test_start_date},
+ status=200)
+ data = json.loads(res.body)
+ count = data['count']
+ self.assertEqual(
+ count[0]['attrib'], test_dates[1][0])
+ self.assertEqual(
+ count[0]['data'], test_dates[1][1])
+ self.assertEqual(
+ count[0]['tstamp'], str(test_dates[1][2]))
+ self.assertEqual(
+ count[1]['attrib'], test_dates[0][0])
+ self.assertEqual(
+ count[1]['data'], test_dates[0][1])
+ self.assertEqual(
+ count[1]['tstamp'], str(test_dates[0][2]))
+ # Test start_date and end_date.
+ self.assertEqual(
+ data['start_date'], str(test_start_date))
+ self.assertEqual(
+ data['end_date'], str(datetime(2013, 11, 30, 9, 9, 9)))
+
+ def user_bookmark_count_authorization(self):
+ """If no API_KEY is present, it is unauthorized request"""
+ self.testapp.get(u'/api/v1/admin/stats/bmarkcount',
+ status=403)
+
def test_account_information(self):
"""Test getting a user's account information"""
res = self.testapp.get(u'/api/v1/admin/account?api_key=' + API_KEY,
View
28 bookie/views/api.py
@@ -28,6 +28,7 @@
from bookie.models.auth import get_random_word
from bookie.models.auth import User
from bookie.models.auth import UserMgr
+from bookie.models.stats import StatBookmarkMgr
from bookie.models.queue import ImportQueueMgr
from bookie.models.fulltext import get_fulltext_handler
@@ -365,6 +366,33 @@ def bmark_recent(request, with_content=False):
})
+@view_config(route_name="api_count_bmarks_user", renderer="jsonp")
+@api_auth('api_key', UserMgr.get, anon=False)
+def user_bmark_count(request):
+ """Get the user's daily bookmark total for the given time window"""
+ params = request.params
+
+ username = request.user.username
+ start_date = params.get('start_date', None)
+ end_date = params.get('end_date', None)
+ bmark_count_list = StatBookmarkMgr.count_user_bmarks(
+ username=username,
+ start_date=start_date,
+ end_date=end_date
+ )
+
+ result_set = []
+ for res in bmark_count_list[0]:
+ return_obj = dict(res)
+
+ result_set.append(return_obj)
+ return _api_response(request, {
+ 'count': result_set,
+ 'start_date': str(bmark_count_list[1]),
+ 'end_date': str(bmark_count_list[2])
+ })
+
+
@view_config(route_name="api_bmarks_popular", renderer="jsonp")
@view_config(route_name="api_bmarks_popular_user", renderer="jsonp")
@api_auth('api_key', UserMgr.get, anon=True)
View
52 docs/api.rst
@@ -552,6 +552,58 @@ Example
}
+/:username/stats/bmarkcount
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Usage
+''''''
+*GET* `/api/v1/admin/stats/bmarkcount`
+
+Get a json dump of the bookmark count for a user's account for a time period.
+The time period can be specified or else a json dump of the bookmark count of
+the past 30 days will be returned. If the start_date is specified to be the
+first day of the month and the end_date is not supplied, a json response of
+the bookmark count of the whole month will be returned.
+
+:query param: api_key *required* - the api key for your account to make the call with
+:query param: start_date *optional* - Find the bookmark count in the specified time window,
+ beginning with start_date.
+:query param: end_date *optional* - Find the bookmark count in the specified time window,
+ ending with end_date.
+
+Status Codes
+''''''''''''
+:success 200: If successful a "200 OK" will be returned
+:error 403: if the api key is not valid or missing then this is an unauthorized request
+
+Example
+'''''''
+::
+
+ requests.get('http://127.0.0.1:6543/api/v1/admin/stats/bmarkcount?start_date=2014-03-01&end_date=2014-03-05&api_key=12345..')
+ >>> {
+ "count": [
+ {
+ "attrib": "user_bookmarks_admin",
+ "data": 0,
+ "id": 1,
+ "tstamp": "2014-03-02 20:50:52"
+ },
+ {
+ "attrib": "user_bookmarks_admin",
+ "data": 3,
+ "id": 10,
+ "tstamp": "2014-03-03 20:50:52"
+ },
+ {
+ "attrib": "user_bookmarks_admin",
+ "data": 5,
+ "id": 21,
+ "tstamp": "2014-03-04 20:50:52"
+ }
+ ]
+ }
+
/:username/tags/complete
~~~~~~~~~~~~~~~~~~~~~~~~~
Something went wrong with that request. Please try again.