Skip to content

Commit

Permalink
Merge branch 'docs-data'
Browse files Browse the repository at this point in the history
  • Loading branch information
gentlecat committed Mar 13, 2015
2 parents 1a5fabf + 1e269fc commit e733523
Show file tree
Hide file tree
Showing 27 changed files with 104 additions and 34 deletions.
2 changes: 1 addition & 1 deletion critiquebrainz/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def init(servers, namespace="CB", debug=0):
"""
global _mc, _glob_namespace
_mc = memcache.Client(servers, debug=debug)
# TODO: Check length of the namespace (should fit with hash appended):
# TODO(roman): Check length of the namespace (should fit with hash appended):
_glob_namespace = namespace + ":"


Expand Down
3 changes: 2 additions & 1 deletion critiquebrainz/data/export_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ def public(location=os.path.join(os.getcwd(), 'export', 'public'), rotate=False)
print("Done!")


# TODO(roman): Improve name of this command ("export importer" sounds kind of strange):
@manager.command
def importer(archive):
"""Imports database dump (archive) produced by export command.
Expand All @@ -227,7 +228,7 @@ def importer(archive):
archive requires is different from the current. Make sure you have the latest dump available.
"""
with tarfile.open(archive, 'r:bz2') as archive:
# TODO: Read data from the archive without extracting it into temporary directory
# TODO(roman): Read data from the archive without extracting it into temporary directory.
temp_dir = tempfile.mkdtemp()
archive.extractall(temp_dir)

Expand Down
8 changes: 4 additions & 4 deletions critiquebrainz/data/model/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def list(cls, release_group=None, user_id=None, sort=None, limit=None,

if sort == 'rating': # order by rating (positive votes - negative votes)

# TODO: Simplify this part. It can probably be rewritten using
# TODO(roman): Simplify this part. It can probably be rewritten using
# hybrid attributes (by making rating property a hybrid_property),
# but I'm not sure how to do that.

Expand Down Expand Up @@ -262,9 +262,9 @@ def get_popular(cls, limit=None):

if not reviews:
# Selecting reviews for distinct release groups
# TODO: The is a problem with selecting popular reviews like this:
# If there are multiple reviews for a release group we don't choose
# the most popular.
# TODO(roman): The is a problem with selecting popular reviews like
# this: if there are multiple reviews for a release group we don't
# choose the most popular.
distinct_subquery = db.session.query(Review) \
.filter(Review.is_draft == False) \
.distinct(Review.release_group).subquery()
Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/data/model/user_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,4 @@ def test_votes(self):

self.assertEqual(len(user.votes), 0)

# TODO: Try to add new votes and see if values change.
# TODO(roman): Try to add new votes and see if values change.
2 changes: 1 addition & 1 deletion critiquebrainz/data/model/vote_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ def test_vote_create(self):
self.assertIn(vote_u1_positive, votes)
self.assertIn(vote_u2_negative, votes)

# TODO: Test vote overwriting
# TODO(roman): Test vote overwriting.
2 changes: 1 addition & 1 deletion critiquebrainz/data/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def create_app(self):

def setUp(self):
db.create_all()
# TODO: Add stuff form fixtures
# TODO(roman): Add stuff form fixtures.

def tearDown(self):
db.session.remove()
Expand Down
8 changes: 8 additions & 0 deletions critiquebrainz/frontend/apis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
This package (api) provides modules to access external services:
- MusicBrainz (with advanced relationship support)
- Spotify
- mbspotify
See documentation in each module for information about usage.
"""
2 changes: 1 addition & 1 deletion critiquebrainz/frontend/apis/mbspotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def vote(mbid, spotify_uri, user_id):
if _base_url is None or _key is None:
return

# TODO: Catch errors during voting.
# TODO(roman): Catch errors during voting.
requests.post(_base_url + 'mapping/vote?key=' + _key, headers={'Content-Type': 'application/json'},
data=json.dumps({
'mbid': str(mbid),
Expand Down
4 changes: 3 additions & 1 deletion critiquebrainz/frontend/apis/musicbrainz.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""
This module simplifies access to the MusicBrainz webservice. It uses musicbrainzngs package.
This module provides access to the MusicBrainz webservice.
It uses musicbrainzngs package for making requests and parsing results.
Package musicbrainzngs is available at https://pypi.python.org/pypi/musicbrainzngs/.
More information about the MusicBrainz webservice can be found at http://wiki.musicbrainz.org/XML_Web_Service.
Expand Down
9 changes: 6 additions & 3 deletions critiquebrainz/frontend/apis/relationships/artist.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Relationship processor for artist entity.
"""
from urlparse import urlparse
from flask_babel import gettext
import urllib
Expand Down Expand Up @@ -75,10 +78,10 @@ def _url(list):
'icon': 'twitter-16.png',
}.items()))
else:
# TODO: Process other types here
# TODO(roman): Process other types here
pass
except Exception as e:
# TODO: Log error
except Exception as e: # FIXME(roman): Too broad exception clause.
# TODO(roman): Log error.
pass
external_urls.sort()
return external_urls
9 changes: 6 additions & 3 deletions critiquebrainz/frontend/apis/relationships/release_group.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Relationship processor for release group entity.
"""
from urlparse import urlparse
from flask_babel import gettext
import urllib
Expand Down Expand Up @@ -41,10 +44,10 @@ def _url(list):
'icon': 'wikipedia-16.png',
}.items()))
else:
# TODO: Process other types here
# TODO(roman): Process other types here
pass
except Exception as e:
# TODO: Log error
except Exception as e: # FIXME(roman): Too broad exception clause.
# TODO(roman): Log error.
pass
external_urls.sort()
return external_urls
2 changes: 1 addition & 1 deletion critiquebrainz/frontend/apis/spotify.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
This module provides functions that can help access Spotify Web API.
This module provides access to Spotify Web API.
More information about it is available at https://developer.spotify.com/web-api/.
"""
Expand Down
7 changes: 6 additions & 1 deletion critiquebrainz/frontend/artist/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

@artist_bp.route('/<uuid:id>')
def entity(id):
"""Artist page.
Displays release groups (split up into several sections depending on their
type), artist information (type, members/member of, external links).
"""
artist = musicbrainz.get_artist_by_id(id)
if not artist:
raise NotFound(gettext("Sorry, we couldn't find an artist with that MusicBrainz ID."))
Expand Down Expand Up @@ -36,7 +41,7 @@ def entity(id):
count, release_groups = musicbrainz.browse_release_groups(artist_id=id, release_types=[release_type],
limit=limit, offset=offset)
for release_group in release_groups:
# TODO: Count reviews instead of fetching them
# TODO(roman): Count reviews instead of fetching them.
reviews, review_count = Review.list(release_group=release_group['id'], sort='created', limit=1)
release_group['review_count'] = review_count
return render_template('artist.html', id=id, artist=artist, release_type=release_type,
Expand Down
5 changes: 5 additions & 0 deletions critiquebrainz/frontend/login/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
Package login provides authentication functionality for CritiqueBrainz.
It is based on OAuth2 protocol. MusicBrainz is the only supported provider.
"""
from flask import redirect, url_for
from flask_login import LoginManager, current_user
from flask_babel import gettext
Expand Down
8 changes: 8 additions & 0 deletions critiquebrainz/frontend/mapping/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Package mapping is basically an interface for mbspotify project.
It allows users to create mappings between release groups and albums on
Spotify. These mappings are then used to show embedded Spotify player on some
pages. See https://github.com/metabrainz/mbspotify for more info about this
project.
"""
18 changes: 16 additions & 2 deletions critiquebrainz/frontend/mapping/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

@mapping_bp.route('/<uuid:release_group_id>')
def spotify_list(release_group_id):
"""This view lists all Spotify albums mapped to a specified release group."""
spotify_mappings = mbspotify.mappings(str(release_group_id))

# Converting Spotify URIs to IDs
Expand Down Expand Up @@ -60,6 +61,7 @@ def spotify():
@mapping_bp.route('/spotify/confirm', methods=['GET', 'POST'])
@login_required
def spotify_confirm():
"""Confirmation page for adding new Spotify mapping."""
release_group_id = request.args.get('release_group_id')
release_group = musicbrainz.get_release_group_by_id(release_group_id)
if not release_group:
Expand All @@ -82,7 +84,7 @@ def spotify_confirm():
return redirect(url_for('.spotify', release_group_id=release_group_id))

if request.method == 'POST':
# TODO: Check returned values that are returned by add_mapping (also take a look at related JS)
# TODO(roman): Check values that are returned by add_mapping (also take a look at related JS).
mbspotify.add_mapping(release_group_id, 'spotify:album:%s' % spotify_id, current_user.id)
flash(gettext("Spotify mapping has been added!"), 'success')
return redirect(url_for('.spotify_list', release_group_id=release_group_id))
Expand All @@ -93,6 +95,10 @@ def spotify_confirm():
@mapping_bp.route('/spotify/report', methods=['GET', 'POST'])
@login_required
def spotify_report():
"""Endpoint for reporting incorrect Spotify mappings.
Shows confirmation page before submitting report to mbspotify.
"""
release_group_id = request.args.get('release_group_id')
spotify_id = request.args.get('spotify_id')
spotify_uri = "spotify:album:" + spotify_id
Expand Down Expand Up @@ -124,13 +130,21 @@ def spotify_report():


def parse_spotify_id(spotify_ref):
"""Extracts Spotify ID out of reference to an album on Spotify.
Supported reference types:
- Spotify URI (spotify:album:6IH6co1QUS7uXoyPDv0rIr)
- HTTP link (http://open.spotify.com/album/6IH6co1QUS7uXoyPDv0rIr)
"""
# Spotify URI
if spotify_ref.startswith('spotify:album:'):
return spotify_ref[14:]

# Link to Spotify
# TODO: Improve checking there. See https://bitbucket.org/metabrainz/critiquebrainz/pull-request/167/cb-115-support-for-different-types-of/activity#comment-2757329
# TODO(roman): Improve checking there. See https://bitbucket.org/metabrainz/critiquebrainz/pull-request/167/cb-115-support-for-different-types-of/activity#comment-2757329
if spotify_ref.startswith('http://') or spotify_ref.startswith('https://'):
if spotify_ref.endswith('/'):
spotify_ref = spotify_ref[:-1]
return os.path.split(urlparse(spotify_ref).path)[-1]

# TODO(roman): Raise exception if failed to parse!
2 changes: 1 addition & 1 deletion critiquebrainz/frontend/release_group/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ def test_release_group_page(self):
self.assert200(response)
self.assertIn("Days Are Gone", response.data)
self.assertIn("No reviews found", response.data)
# TODO: Try to add review and check it's displayed there!
# TODO(roman): Try to add review and check it's displayed there!
1 change: 1 addition & 0 deletions critiquebrainz/frontend/search/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def search_wrapper(query, type, offset=None):
count, results = 0, []
return count, results


@search_bp.route('/')
def index():
query = request.args.get('query')
Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/frontend/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def create_app(self):

def setUp(self):
db.create_all()
# TODO: Add stuff form fixtures
# TODO(roman): Add stuff form fixtures.

def tearDown(self):
db.session.remove()
Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/frontend/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def index():
recent_reviews, _ = Review.list(sort='created', limit=9)

# Statistics
# TODO: Move these into models:
# TODO(roman): Move these into models:
review_count = format_number(Review.query.filter(Review.is_draft == False).count())
user_count = format_number(User.query.count())

Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/ws/oauth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def oauth_token_handler():
raise UnsupportedGrantType("Specified grant_type is unsupported. Please, use authorization_code or refresh_token.")

# Deleting grant and/or existing token(s)
# TODO: Check if that's necessary
# TODO(roman): Check if that's necessary:
oauth.discard_grant(client_id, code)
oauth.discard_client_user_tokens(client_id, user_id)

Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/ws/review/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def review_list_handler():
if language and language not in supported_languages:
raise InvalidRequest(desc='Unsupported language')

# TODO: Ideally caching logic should live inside the model. Otherwise it
# TODO(roman): Ideally caching logic should live inside the model. Otherwise it
# becomes hard to track all this stuff.
cache_key = cache.gen_key('list', release_group, user_id, sort, limit, offset, language)
cached_result = cache.get(cache_key, Review.CACHE_NAMESPACE)
Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/ws/review/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ def test_review_creation(self):
self.assertEqual(resp['count'], 1)
self.assertEqual(len(resp['reviews']), 1)
self.assertEqual(resp['reviews'][0]['id'], review.id)
# TODO: Completely verify output (I encountered unicode issues when tried to do that).
# TODO(roman): Completely verify output (I encountered unicode issues when tried to do that).
2 changes: 1 addition & 1 deletion critiquebrainz/ws/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def create_app(self):

def setUp(self):
db.create_all()
# TODO: Add stuff form fixtures
# TODO(roman): Add stuff form fixtures.

def tearDown(self):
db.session.remove()
Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/ws/user/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ def test_user_addition(self):
resp = self.client.get('/user/').json
self.assertEqual(resp['count'], 1)
self.assertEqual(len(resp['users']), 1)
# TODO: Completely verify output (I encountered unicode issues when tried to do that).
# TODO(roman): Completely verify output (I encountered unicode issues when tried to do that).
28 changes: 24 additions & 4 deletions docs/contrib/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,38 @@ First, you need to create custom configuration file. Copy the skeleton configura
Then, open ``critiquebrainz/config.py`` in your favourite text editor, uncomment
``SQLALCHEMY_DATABASE_URI`` variable, and fill in the fields in angle brackets.

Database initialization
^^^^^^^^^^^^^^^^^^^^^^^

Now, you need to create and configure the database with::

$ python manage.py data create_db
$ python manage.py create_db

This command will

* create new PostgreSQL role, if needed
* create new PostgreSQL database, if needed
* register ``uuid-ossp`` PostgreSQL extension, if needed

You also need to update the newly created database with default schema
and testing data. To do this type::
You also need to add initial data for models (predefined licenses). To do this
use ``fixtures`` command::

$ python manage.py fixtures

Importing data
""""""""""""""

$ python manage.py data fixtures
We provide daily data dumps from https://critiquebrainz.org that include reviews
and most of the data associated with them. If you want to import that into your
own installation, download archives from ftp://ftp.musicbrainz.org/pub/musicbrainz/critiquebrainz/dump/
(you'll need to get the base archive ``cbdump.tar.bz2`` and one with reviews)
and use ``python manage.py export importer`` command. First you need to import
base archive and then one that contains reviews. For example::

$ python manage.py export importer cbdump.tar.bz2
$ python manage.py export importer cbdump-reviews-all.tar.bz2

Keep in mind that CritiqueBrainz only supports importing into an empty database.

Preparing login
^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -114,4 +132,6 @@ https://www.owasp.org/index.php/Top_10_2010-A9-Insufficient_Transport_Layer_Prot
Running the server
------------------

To run the server you can use ``run.py`` script::

$ python run.py
2 changes: 1 addition & 1 deletion import.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This script imports reviews from BBC's MySQL dump into CritiqueBrainz server.
# Note: Before running it, dump has to be imported into local MySQL instance!

# TODO: Create proper importing functionality and integrate it into data package.
# TODO(roman): Create proper importing functionality and integrate it into data package.

from __future__ import print_function
import re
Expand Down

0 comments on commit e733523

Please sign in to comment.