Skip to content

Commit

Permalink
CB-231: Use direct database access for entity: event
Browse files Browse the repository at this point in the history
  • Loading branch information
ferbncode authored and gentlecat committed Aug 17, 2017
1 parent e93310e commit ff68102
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 20 deletions.
99 changes: 99 additions & 0 deletions critiquebrainz/frontend/external/musicbrainz_db/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from collections import defaultdict
from mbdata import models
from critiquebrainz.frontend.external.musicbrainz_db import mb_session, DEFAULT_CACHE_EXPIRATION
from critiquebrainz.frontend.external.musicbrainz_db.utils import get_entities_by_gids
from critiquebrainz.frontend.external.musicbrainz_db.includes import check_includes
from critiquebrainz.frontend.external.musicbrainz_db.serialize import to_dict_events
from critiquebrainz.frontend.external.musicbrainz_db.helpers import get_relationship_info
from brainzutils import cache


def get_event_by_id(mbid):
"""Get event with the MusicBrainz ID.
Args:
mbid (uuid): MBID(gid) of the event.
Returns:
Dictionary containing the event information.
"""
key = cache.gen_key(mbid)
event = cache.get(key)
if not event:
event = _get_event_by_id(mbid)
cache.set(key=key, val=event, time=DEFAULT_CACHE_EXPIRATION)
return event


def _get_event_by_id(mbid):
return fetch_multiple_events(
[mbid],
includes=['artist-rels', 'place-rels', 'series-rels', 'url-rels', 'release-group-rels'],
).get(mbid)


def fetch_multiple_events(mbids, *, includes=None):
"""Get info related to multiple events using their MusicBrainz IDs.
Args:
mbids (list): List of MBIDs of events.
includes (list): List of information to be included.
Returns:
Dictionary containing info of multiple events keyed by their mbid.
"""
if includes is None:
includes = []
includes_data = defaultdict(dict)
check_includes('event', includes)
with mb_session() as db:
query = db.query(models.Event)
events = get_entities_by_gids(
query=query,
entity_type='event',
mbids=mbids,
)
event_ids = [event.id for event in events.values()]

if 'artist-rels' in includes:
get_relationship_info(
db=db,
target_type='artist',
source_type='event',
source_entity_ids=event_ids,
includes_data=includes_data,
)
if 'place-rels' in includes:
get_relationship_info(
db=db,
target_type='place',
source_type='event',
source_entity_ids=event_ids,
includes_data=includes_data,
)
if 'series-rels' in includes:
get_relationship_info(
db=db,
target_type='series',
source_type='event',
source_entity_ids=event_ids,
includes_data=includes_data,
)
if 'url-rels' in includes:
get_relationship_info(
db=db,
target_type='url',
source_type='event',
source_entity_ids=event_ids,
includes_data=includes_data,
)
if 'release-group-rels' in includes:
get_relationship_info(
db=db,
target_type='release_group',
source_type='event',
source_entity_ids=event_ids,
includes_data=includes_data,
)

events = {str(mbid): to_dict_events(events[mbid], includes_data[events[mbid].id]) for mbid in mbids}
return events
7 changes: 4 additions & 3 deletions critiquebrainz/frontend/external/musicbrainz_db/helpers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from mbdata.utils.models import get_entity_type_model, get_link_model
from mbdata.utils.models import get_link_model
from mbdata.models import Tag
from sqlalchemy.orm import joinedload
from sqlalchemy import func
from critiquebrainz.frontend.external.musicbrainz_db.utils import ENTITY_MODELS


def get_relationship_info(*, db, target_type, source_type, source_entity_ids, includes_data):
Expand All @@ -17,8 +18,8 @@ def get_relationship_info(*, db, target_type, source_type, source_entity_ids, in
source_entity_ids (list): IDs of the source entity.
includes_data (dict): Dictionary containing includes data of entities.
"""
source_model = get_entity_type_model(source_type)
target_model = get_entity_type_model(target_type)
source_model = ENTITY_MODELS[source_type]
target_model = ENTITY_MODELS[target_type]
relation = get_link_model(source_model, target_model)

query = db.query(relation).\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
RATING_INCLUDES = ["ratings", "user-ratings"]
VALID_INCLUDES = {
'place': ["aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES,
'event': ["aliases"] + RELATION_INCLUDES + TAG_INCLUDES,
'release_group': ["artists", "media", "releases"] + TAG_INCLUDES + RELATION_INCLUDES,
}

Expand Down
31 changes: 29 additions & 2 deletions critiquebrainz/frontend/external/musicbrainz_db/serialize.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from mbdata.utils.models import ENTITY_TYPES, get_link_target
from mbdata.utils.models import get_link_target
from critiquebrainz.frontend.external.musicbrainz_db.utils import ENTITY_MODELS


def to_dict_relationships(data, source_obj, relationship_objs):
Expand All @@ -12,7 +13,7 @@ def to_dict_relationships(data, source_obj, relationship_objs):
Returns:
Dictionary containing lists of dictionaries of related entities.
"""
for entity_type in ENTITY_TYPES:
for entity_type in ENTITY_MODELS:
relation = '{entity_type}-rels'.format(entity_type=entity_type)
if relation in relationship_objs:
data[relation] = []
Expand Down Expand Up @@ -144,11 +145,37 @@ def to_dict_releases(release, includes=None):
return data


def to_dict_events(event, includes=None):
if includes is None:
includes = {}
data = {
'id': event.gid,
'name': event.name,
}
if 'relationship_objs' in includes:
to_dict_relationships(data, event, includes['relationship_objs'])
return data


def to_dict_series(series, includes=None):
if includes is None:
includes = []
data = {
'id': series.gid,
'name': series.name,
}
if 'relationship_objs' in includes:
to_dict_relationships(data, series, includes['relationship_objs'])
return data


TO_DICT_ENTITIES = {
'artist': to_dict_artists,
'url': to_dict_urls,
'place': to_dict_places,
'release_group': to_dict_release_groups,
'area': to_dict_areas,
'release': to_dict_releases,
'event': to_dict_events,
'series': to_dict_series,
}
30 changes: 30 additions & 0 deletions critiquebrainz/frontend/external/musicbrainz_db/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
ReleaseGroupPrimaryType,
ReleaseStatus,
Script,
Event,
EventType,
Track,
)

Expand Down Expand Up @@ -331,3 +333,31 @@
releasegroup_collision_course.gid = '8ef859e3-feb2-4dd1-93da-22b91280d768'
releasegroup_collision_course.name = 'Collision Course'
releasegroup_collision_course.meta = releasegroupmeta_1

eventtype_festival = EventType()
eventtype_festival.id = 2
eventtype_festival.name = 'Festival'
eventtype_festival.description = 'An event where a number of different acts perform across the course of the day. Larger festivals may be spread across multiple days.'
eventtype_festival.gid = 'b6ded574-b592-3f0e-b56e-5b5f06aa0678'

taubertal_festival_2004 = Event()
taubertal_festival_2004.id = 1607
taubertal_festival_2004.gid = 'ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94'
taubertal_festival_2004.name = 'Taubertal-Festival 2004, Day 1'
taubertal_festival_2004.cancelled = False
taubertal_festival_2004.ended = True
taubertal_festival_2004.type = eventtype_festival

eventtype_concert = EventType()
eventtype_concert.id = 1
eventtype_concert.name = 'Concert'
eventtype_concert.description = 'An individual concert by a single artist or collaboration, often with supporting artists who perform before the main act.'
eventtype_concert.gid = 'ef55e8d7-3d00-394a-8012-f5506a29ff0b'

event_ra_hall_uk = Event()
event_ra_hall_uk.id = 21675
event_ra_hall_uk.gid = '40e6153d-a042-4c95-a0a9-b0a47e3825ce'
event_ra_hall_uk.name = '1996-04-17: Royal Albert Hall, London, England, UK'
event_ra_hall_uk.cancelled = False
event_ra_hall_uk.ended = True
event_ra_hall_uk.type = eventtype_concert
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from unittest import TestCase
from unittest.mock import MagicMock
from critiquebrainz.frontend.external.musicbrainz_db import event as mb_event
from critiquebrainz.frontend.external.musicbrainz_db.test_data import taubertal_festival_2004, event_ra_hall_uk
from critiquebrainz.frontend.external.musicbrainz_db.tests import setup_cache

class EventTestCase(TestCase):

def setUp(self):
setup_cache()
mb_event.mb_session = MagicMock()
self.mock_db = mb_event.mb_session.return_value.__enter__.return_value
self.event_query = self.mock_db.query.return_value.filter.return_value.all

def test_get_event_by_id(self):
self.event_query.return_value = [taubertal_festival_2004]
event = mb_event.get_event_by_id('ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94')
self.assertDictEqual(event, {
'id': 'ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94',
'name': 'Taubertal-Festival 2004, Day 1',
})

def test_fetch_multiple_events(self):
self.event_query.return_value = [taubertal_festival_2004, event_ra_hall_uk]
events = mb_event.fetch_multiple_events(
['ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94', '40e6153d-a042-4c95-a0a9-b0a47e3825ce'],
)
self.assertEqual(events['ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94']['name'], 'Taubertal-Festival 2004, Day 1')
self.assertEqual(events['40e6153d-a042-4c95-a0a9-b0a47e3825ce']['name'], '1996-04-17: Royal Albert Hall, London, England, UK')
2 changes: 2 additions & 0 deletions critiquebrainz/frontend/external/musicbrainz_db/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
'release_group': models.ReleaseGroup,
'release': models.Release,
'event': models.Event,
'series': models.Series,
'url': models.URL,
}


Expand Down
12 changes: 6 additions & 6 deletions critiquebrainz/frontend/templates/event/entity.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ <h2 class="pull-left">
{% endif %}
</div>

{% if event['place-relation-list'] %}
{% set place = event['place-relation-list'][0]['place'] %}
{% if event['place-rels'] %}
{% set place = event['place-rels'][0]['place'] %}
{% if place['coordinates'] %}
{% set lat = place['coordinates']['latitude'] | float %}
{% set long = place['coordinates']['longitude'] | float %}
Expand Down Expand Up @@ -102,13 +102,13 @@ <h4 style="margin-bottom:0;">{{ _('Reviews') }}</h4>
<div class="col-md-3">
<h4>{{ _('Event information') }}</h4>

{% if 'release_group-relation-list' in event %}
{% for rg in event['release_group-relation-list'] %}
<p><b>{{ rg['type'] | title }}:</b> <a href="{{ url_for('release_group.entity', id=rg['target']) }}">{{ rg['release-group']['title'] }}</a></p>
{% if 'release_group-rels' in event %}
{% for rg in event['release_group-rels'] %}
<p><b>{{ rg['type'] | title }}:</b> <a href="{{ url_for('release_group.entity', id=rg['release_group']['id']) }}">{{ rg['release_group']['title'] }}</a></p>
{% endfor %}
{% endif %}

{% if 'artist-relation-list' in event %}
{% if 'artist-rels' in event %}
{% for type, artists in event['artists_grouped'] %}
<b>{{ type | title }}</b>
<ul class="list-unstyled">
Expand Down
20 changes: 11 additions & 9 deletions critiquebrainz/frontend/views/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from flask import Blueprint, render_template, request
from flask_login import current_user
from flask_babel import gettext
from critiquebrainz.frontend.external import musicbrainz
import critiquebrainz.db.review as db_review
from werkzeug.exceptions import NotFound
import critiquebrainz.db.review as db_review
import critiquebrainz.frontend.external.musicbrainz_db.event as mb_event
import critiquebrainz.frontend.external.musicbrainz_db.exceptions as mb_exceptions


event_bp = Blueprint('event', __name__)
Expand All @@ -14,16 +15,17 @@
@event_bp.route('/<uuid:id>')
def entity(id):
id = str(id)
event = musicbrainz.get_event_by_id(id)
if not event:
try:
event = mb_event.get_event_by_id(id)
except mb_exceptions.NoDataFoundException:
raise NotFound(gettext("Sorry, we couldn't find a event with that MusicBrainz ID."))

if 'artist-relation-list' in event and event['artist-relation-list']:
artists_sorted = sorted(event['artist-relation-list'], key=itemgetter('type'))
if 'artist-rels' in event and event['artist-rels']:
artists_sorted = sorted(event['artist-rels'], key=itemgetter('type'))
event['artists_grouped'] = groupby(artists_sorted, itemgetter('type'))

if current_user.is_authenticated:
my_reviews, my_count = db_review.list_reviews(entity_id=id, entity_type='event', user_id=current_user.id)
my_reviews, my_count = db_review.list_reviews(entity_id=event['id'], entity_type='event', user_id=current_user.id)
if my_count != 0:
my_review = my_reviews[0]
else:
Expand All @@ -33,7 +35,7 @@ def entity(id):

limit = int(request.args.get('limit', default=10))
offset = int(request.args.get('offset', default=0))
reviews, count = db_review.list_reviews(entity_id=id, entity_type='event', sort='popularity', limit=limit, offset=offset)
reviews, count = db_review.list_reviews(entity_id=event['id'], entity_type='event', sort='popularity', limit=limit, offset=offset)

return render_template('event/entity.html', id=id, event=event, reviews=reviews,
return render_template('event/entity.html', id=event['id'], event=event, reviews=reviews,
my_review=my_review, limit=limit, offset=offset, count=count)

0 comments on commit ff68102

Please sign in to comment.