Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-359: Implemented the reviewal of labels #264

Merged
merged 11 commits into from
Aug 15, 2019
1 change: 1 addition & 0 deletions admin/schema_changes/16.sql
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ALTER TYPE entity_types ADD VALUE 'artist' AFTER 'place';
ALTER TYPE entity_types ADD VALUE 'label' AFTER 'artist';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just saw this, this should be in a different script so I can run it on the main db. Generally, each PR should have a single schema change script.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. @spellew Please add schema change scripts to admin/schema_changes (One for artists and one for labels)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @paramsingh for pointing that out :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for fixing it too.

3 changes: 2 additions & 1 deletion admin/sql/create_types.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ CREATE TYPE entity_types AS ENUM (
'release_group',
'event',
'place',
'artist'
'artist',
'label'
);
1 change: 1 addition & 0 deletions critiquebrainz/db/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"place",
"release_group",
"artist",
"label",
]


Expand Down
2 changes: 2 additions & 0 deletions critiquebrainz/frontend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def create_app(debug=None, config_path=None):
from critiquebrainz.frontend.views.review import review_bp
from critiquebrainz.frontend.views.search import search_bp
from critiquebrainz.frontend.views.artist import artist_bp
from critiquebrainz.frontend.views.label import label_bp
from critiquebrainz.frontend.views.release_group import release_group_bp
from critiquebrainz.frontend.views.release import release_bp
from critiquebrainz.frontend.views.event import event_bp
Expand All @@ -152,6 +153,7 @@ def create_app(debug=None, config_path=None):
app.register_blueprint(review_bp, url_prefix='/review')
app.register_blueprint(search_bp, url_prefix='/search')
app.register_blueprint(artist_bp, url_prefix='/artist')
app.register_blueprint(label_bp, url_prefix='/label')
app.register_blueprint(release_group_bp, url_prefix='/release-group')
app.register_blueprint(release_bp, url_prefix='/release')
app.register_blueprint(event_bp, url_prefix='/event')
Expand Down
6 changes: 6 additions & 0 deletions critiquebrainz/frontend/external/musicbrainz.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ def search_places(query='', limit=None, offset=None):
"""Search for places."""
api_resp = musicbrainzngs.search_places(query=query, limit=limit, offset=offset)
return api_resp.get('place-count'), api_resp.get('place-list')


def search_labels(query='', limit=None, offset=None):
"""Search for labels."""
api_resp = musicbrainzngs.search_labels(query=query, limit=limit, offset=offset)
return api_resp.get('label-count'), api_resp.get('label-list')
8 changes: 8 additions & 0 deletions critiquebrainz/frontend/external/musicbrainz_db/entities.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from brainzutils.musicbrainz_db.artist import fetch_multiple_artists
from brainzutils.musicbrainz_db.label import fetch_multiple_labels
from brainzutils.musicbrainz_db.place import fetch_multiple_places
from brainzutils.musicbrainz_db.event import fetch_multiple_events
from brainzutils.musicbrainz_db.release_group import fetch_multiple_release_groups
from critiquebrainz.frontend.external.musicbrainz_db.release_group import get_release_group_by_id
from critiquebrainz.frontend.external.musicbrainz_db.place import get_place_by_id
from critiquebrainz.frontend.external.musicbrainz_db.event import get_event_by_id
from critiquebrainz.frontend.external.musicbrainz_db.label import get_label_by_id
from critiquebrainz.frontend.external.musicbrainz_db.artist import get_artist_by_id


Expand All @@ -26,6 +28,7 @@ def get_multiple_entities(entities):
entities_info = {}
release_group_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'release_group', entities)]
artist_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'artist', entities)]
label_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'label', entities)]
place_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'place', entities)]
event_mbids = [entity[0] for entity in filter(lambda entity: entity[1] == 'event', entities)]
entities_info.update(fetch_multiple_release_groups(
Expand All @@ -35,6 +38,9 @@ def get_multiple_entities(entities):
entities_info.update(fetch_multiple_artists(
artist_mbids,
))
entities_info.update(fetch_multiple_labels(
label_mbids,
))
entities_info.update(fetch_multiple_places(
place_mbids,
))
Expand All @@ -50,6 +56,8 @@ def get_entity_by_id(id, type='release_group'):
entity = get_release_group_by_id(str(id))
elif type == 'artist':
entity = get_artist_by_id(str(id))
elif type == 'label':
entity = get_label_by_id(str(id))
elif type == 'place':
entity = get_place_by_id(str(id))
elif type == 'event':
Expand Down
23 changes: 23 additions & 0 deletions critiquebrainz/frontend/external/musicbrainz_db/label.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from brainzutils import cache
from brainzutils.musicbrainz_db.label import fetch_multiple_labels
from critiquebrainz.frontend.external.musicbrainz_db import DEFAULT_CACHE_EXPIRATION
from critiquebrainz.frontend.external.relationships import label as label_rel


def get_label_by_id(mbid):
"""Get label with MusicBrainz ID.

Args:
mbid (uuid): MBID(gid) of the label.
Returns:
Dictionary containing the label information
"""
key = cache.gen_key(mbid)
label = cache.get(key)
if not label:
label = fetch_multiple_labels(
[mbid],
includes=['artist-rels', 'url-rels'],
).get(mbid)
cache.set(key=key, val=label, time=DEFAULT_CACHE_EXPIRATION)
return label_rel.process(label)
ferbncode marked this conversation as resolved.
Show resolved Hide resolved
76 changes: 76 additions & 0 deletions critiquebrainz/frontend/external/relationships/label.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Relationship processor for label entity.
"""
import urllib.parse
from flask_babel import lazy_gettext


def process(label):
"""Handles processing supported relation lists."""
if 'url-rels' in label and label['url-rels']:
label['external-urls'] = _url(label['url-rels'])
return label


def _url(url_list):
"""Processor for Label-URL relationship."""
basic_types = {
'wikidata': {'name': lazy_gettext('Wikidata'), 'icon': 'wikidata-16.png', },
'discogs': {'name': lazy_gettext('Discogs'), 'icon': 'discogs-16.png', },
'allmusic': {'name': lazy_gettext('Allmusic'), 'icon': 'allmusic-16.png', },
'bandcamp': {'name': lazy_gettext('Bandcamp'), 'icon': 'bandcamp-16.png', },
'official homepage': {'name': lazy_gettext('Official homepage'), 'icon': 'home-16.png', },
'BBC Music page': {'name': lazy_gettext('BBC Music'), },
}
external_urls = []
for relation in url_list:
if relation['type'] in basic_types:
external_urls.append(dict(list(relation.items()) + list(basic_types[relation['type']].items())))
else:
try:
target = urllib.parse.urlparse(relation['target'])
if relation['type'] == 'lyrics':
external_urls.append(dict(
relation.items() + {
'name': lazy_gettext('Lyrics'),
'disambiguation': target.netloc,
}.items()))
elif relation['type'] == 'wikipedia':
external_urls.append(dict(
relation.items() + {
'name': lazy_gettext('Wikipedia'),
'disambiguation': (
target.netloc.split('.')[0] +
':' +
urllib.parse.unquote(target.path.split('/')[2]).decode('utf8').replace("_", " ")
),
'icon': 'wikipedia-16.png',
}.items()))
elif relation['type'] == 'youtube':
path = target.path.split('/')
if path[1] == 'user' or path[1] == 'channel':
disambiguation = path[2]
else:
disambiguation = path[1]
external_urls.append(dict(
relation.items() + {
'name': lazy_gettext('YouTube'),
'disambiguation': disambiguation,
'icon': 'youtube-16.png',
}.items()))
elif relation['type'] == 'social network':
if target.netloc == 'twitter.com':
external_urls.append(dict(
relation.items() + {
'name': lazy_gettext('Twitter'),
'disambiguation': target.path.split('/')[1],
'icon': 'twitter-16.png',
}.items()))
else:
# TODO(roman): Process other types here
pass
except Exception: # FIXME(roman): Too broad exception clause.
# TODO(roman): Log error.
pass

return sorted(external_urls, key=lambda k: k['name'])
7 changes: 7 additions & 0 deletions critiquebrainz/frontend/static/styles/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@artist-color: @blue;
@event-color: @green;
@place-color: @yellow;
@label-color: @blue;

body {
padding-bottom: 25px;
Expand Down Expand Up @@ -131,6 +132,9 @@ ul.sharing {
&.place {
background-color: fade(@place-color, 70%);
}
&.label {
background-color: fade(@label-color, 70%);
}
&.event {
background-color: fade(@event-color, 70%);
}
Expand Down Expand Up @@ -493,6 +497,9 @@ a#edit-review { margin-top: 20px; }
&.place {
background-color: fade(@place-color, 70%);
}
&.label {
background-color: fade(@label-color, 70%);
}
&.event {
background-color: fade(@event-color, 70%);
}
Expand Down
2 changes: 2 additions & 0 deletions critiquebrainz/frontend/templates/entity_review.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
artist = entity['artist-credit-phrase'] | default(_('[Unknown artist]'))) }}
{% elif review.entity_type == 'artist' %}
{{ _('%(artist)s', artist = '<b>'|safe + entity.name | default(_('[Unknown artist]')) + '</b>'|safe) }}
{% elif review.entity_type == 'label' %}
{{ _('%(label)s', label = '<b>'|safe + entity.name | default(_('[Unknown label]')) + '</b>'|safe) }}
{% elif review.entity_type == 'event' %}
{{ _('%(event)s', event = '<b>'|safe + entity.name | default(_('[Unknown event]')) + '</b>'|safe) }}
{% elif review.entity_type == 'place' %}
Expand Down
121 changes: 121 additions & 0 deletions critiquebrainz/frontend/templates/label/entity.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{% extends 'base.html' %}
{% from 'macros.html' import entity_rate_form, show_avg_rating with context %}

{% block title %}{{ label.name }} - CritiqueBrainz{% endblock %}

{% block content %}
<div class="clearfix">
<h2 class="pull-left">
{{ label.name }}
{% if label.disambiguation %}
<small>({{ label.disambiguation }})</small>
{% endif %}
</h2>

{% if not my_review %}
<a id="write-review" href="{{ url_for('review.create', label=id) }}"
role="button" class="btn btn-success pull-right">
<span class="glyphicon glyphicon-asterisk"></span> {{ _('Write a review') }}
</a>
{% else %}
<a id="edit-review" href="{{ url_for('review.edit', id=my_review.id) }}"
role="button" class="btn btn-primary pull-right">
<span class="glyphicon glyphicon-edit"></span> {{ _('Edit my review') }}
</a>
{% endif %}
</div>

<div class="row">
<div class="col-sm-9">
<h4 style="margin-bottom:0;">{{ _('Reviews') }}</h4>
{% if not reviews %}
<p class="lead" style="text-align: center;">{{ _('No reviews found') }}</p>
{% else %}
<table class="table table-condensed table-hover">
<thead>
<tr>
<th></th>
<th>{{ _('Published on') }}</th>
<th>{{ _('Votes (+/-)') }}</th>
</tr>
</thead>
<tbody>
{% for review in reviews %}
<tr data-review-id="{{ review.id }}">
<td>
<a href="{{ url_for('review.entity', id=review.id) }}">
{{ _('by %(reviewer)s', reviewer='<img class="avatar" src="%s&s=16" /> '|safe % review.user.avatar + review.user.display_name) }}
</a>
</td>
<td>{{ review.published_on | date }}</td>
<td>{{ review.votes_positive_count }}/{{ review.votes_negative_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="col-md-12">
<ul class="pager">
{% if not reviews_limit %}
<li class="next"><a href="{{ url_for('label.entity', id=id) }}">{{ _('Hide reviews') }}</a></li>
{% elif reviews_count > reviews_limit %}
<li class="next"><a href="{{ url_for('label.entity', id=id, reviews='all') }}">{{ _('Show all reviews') }}</a></li>
{% endif %}
</ul>
</div>
{% endif %}
<ul class="pagination"></ul>
</div>

<div class="col-sm-3">
<h4>{{ _('Label information') }}</h4>
{% if label.type %}<p class="text-muted">{{ label.type }}</p>{% endif %}

{% if label['external-urls'] %}
<b>{{ _('External links') }}</b>
<ul class="list-unstyled external-links">
{% for url in label['external-urls'] %}
<li class="clearfix">
<div class="favicon-container">
{% if url.icon %}
<img src="{{ get_static_path('favicons/' + url.icon) }}" />
{% else %}
<img src="{{ get_static_path('favicons/external-16.png') }}" />
{% endif %}
</div>
<a href="{{ url.url.url }}">{{ url.name }}</a>
{% if url.disambiguation %}<span class="text-muted">({{ url.disambiguation }})</span>{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}

<div class="external-links">
<div class="favicon-container"><img src="{{ get_static_path('favicons/musicbrainz-16.svg') }}" /></div>
<a href="https://musicbrainz.org/label/{{ label.id }}"><em>{{ _('Edit on MusicBrainz') }}</em></a>
</div>

<br/><br/>
{{ entity_rate_form('label', 'label') }}
{% if avg_rating %}
<div class="avg-rating">
{{ show_avg_rating(avg_rating.rating, avg_rating.count, show_glyphicon = false) }}
</div>
{% endif %}
</div>
</div>
{% endblock %}

{% block scripts %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css"/>
<script>
$(document).ready(function() {
$("#ratestars").click(function(e){
// only submit rating form when user clicks on <i></i> tag (see generated HTML for rating stars on this page)
if (e.target.tagName === 'I') {
$("#rating-form").submit();
}
});
});
</script>
<script src="{{ get_static_path('rating.js') }}"></script>
{% endblock %}
13 changes: 11 additions & 2 deletions critiquebrainz/frontend/templates/macros.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
{{ _('Artist') }}
</span>
{% endif %}
{% elif entity_type == 'label' %}
<img src="{{ get_static_path('images/placeholder_place.svg') }}" {{ attributes }} />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

placeholder_disc.svg would be much relating to labels, imho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

{% if overlay_type %}
<span class="entity-type label">
{{ _('Label') }}
</span>
{% endif %}
{% else %} {# release-group #}
<img {{ attributes }} />
{% if overlay_type %}
Expand Down Expand Up @@ -153,8 +160,10 @@
{% endif %}
{% endmacro %}

{% macro show_avg_rating(rating, count) %}
<i class="glyphicon glyphicon-star"></i>
{% macro show_avg_rating(rating, count, show_glyphicon=True) %}
{% if show_glyphicon %}
<i class="glyphicon glyphicon-star"></i>
{% endif %}
<span style="font-size: 16px;">{{ rating }}</span><em class="text-muted">/5 {{ _('based on %(number)s ratings', number=count) }}</em>
{% endmacro %}

Expand Down
3 changes: 2 additions & 1 deletion critiquebrainz/frontend/templates/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@
<div class="form-group">
<select id="type-selector" name="type" class="form-control input-sm">
<option value="artist">{{ _('Artist') }}</option>
<option value="release-group">{{ _('Release group') }}</option>
<option value="label">{{ _('Label') }}</option>
<option value="event">{{ _('Event') }}</option>
<option value="place">{{ _('Place') }}</option>
<option value="release-group">{{ _('Release group') }}</option>
</select>
</div>
<button type="submit" class="btn input-sm"><span class="glyphicon glyphicon-search"></span></button>
Expand Down
2 changes: 2 additions & 0 deletions critiquebrainz/frontend/templates/review/browse.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ <h2>{{ _('Reviews') }}</h2>
<a href="{{ url_for('review.browse', entity_type='release_group') }}">{{ _('Release group') }}</a></li>
<li role="presentation" {{ "class=active" if entity_type == 'artist' }}>
<a href="{{ url_for('review.browse', entity_type='artist') }}">{{ _('Artist') }}</a></li>
<li role="presentation" {{ "class=active" if entity_type == 'label' }}>
<a href="{{ url_for('review.browse', entity_type='label') }}">{{ _('Label') }}</a></li>
<li role="presentation" {{ "class=active" if entity_type == 'event' }}>
<a href="{{ url_for('review.browse', entity_type='event') }}">{{ _('Event') }}</a></li>
<li role="presentation" {{ "class=active" if entity_type == 'place' }}>
Expand Down
Loading