diff --git a/spa/api/v1/GenreResource.py b/spa/api/v1/GenreResource.py new file mode 100644 index 0000000..a500311 --- /dev/null +++ b/spa/api/v1/GenreResource.py @@ -0,0 +1,19 @@ +from tastypie import fields +from tastypie.authentication import Authentication +from tastypie.authorization import Authorization +from tastypie.exceptions import ImmediateHttpResponse +from tastypie.http import HttpBadRequest, HttpMethodNotAllowed, HttpUnauthorized, HttpApplicationError, HttpNotImplemented +from spa.api.v1.BackboneCompatibleResource import BackboneCompatibleResource +from spa.models import Mix, UserProfile, Genre +from spa.models.comment import Comment + + +class GenreResource(BackboneCompatibleResource): + class Meta: + queryset = Genre.objects.all().order_by('text') + resource_name = 'genres' + + excludes = ['id', 'resource_uri'] + authorization = Authorization() + authentication = Authentication() + always_return_data = True diff --git a/spa/api/v1/MixResource.py b/spa/api/v1/MixResource.py index 2dcb4d7..afe32fe 100755 --- a/spa/api/v1/MixResource.py +++ b/spa/api/v1/MixResource.py @@ -21,209 +21,206 @@ from spa.models.mix import Mix class MixResource(BackboneCompatibleResource): - comments = fields.ToManyField('spa.api.v1.CommentResource.CommentResource', 'comments', null=True, full=True) - favourites = fields.ToManyField('spa.api.v1.UserResource.UserResource', 'favourites', - related_name='favourites', full=False, null=True) + comments = fields.ToManyField('spa.api.v1.CommentResource.CommentResource', 'comments', null=True, full=True) + favourites = fields.ToManyField('spa.api.v1.UserResource.UserResource', 'favourites', related_name='favourites', full=False, null=True) + likes = fields.ToManyField('spa.api.v1.UserResource.UserResource', 'likes', related_name='likes', full=False, null=True) + genres = fields.ToManyField('spa.api.v1.GenreResource.GenreResource', 'genres', related_name='genres', full=True, null=True) - likes = fields.ToManyField('spa.api.v1.UserResource.UserResource', 'likes', - related_name='likes', full=False, null=True) + class Meta: + queryset = Mix.objects.filter(is_active=True) + user = ToOneField('UserResource', 'user') + always_return_data = True + detail_uri_name = 'slug' + excludes = ['is_active', 'local_file', 'waveform-generated'] + post_excludes = ['comments'] + filtering = { + 'comments': ALL_WITH_RELATIONS, + 'genres': ALL_WITH_RELATIONS, + 'favourites': ALL_WITH_RELATIONS, + 'likes': ALL_WITH_RELATIONS, + 'slug': ALL_WITH_RELATIONS, + } + authorization = Authorization() - class Meta: - queryset = Mix.objects.filter(is_active=True) - user = ToOneField('UserResource', 'user') - always_return_data = True - detail_uri_name = 'slug' - excludes = ['is_active', 'local_file', 'waveform-generated'] - post_excludes = ['comments'] - filtering = { - 'comments': ALL_WITH_RELATIONS, - 'favourites': ALL_WITH_RELATIONS, - 'likes': ALL_WITH_RELATIONS, - 'slug': ALL_WITH_RELATIONS, - } - authorization = Authorization() + def _parseGenreList(self, genres): + #for magic.. + ret = [] + for genre in genres: + if genre['id'] == genre['text']: + new_item = Genre(description=genre['text']) + new_item.save() + ret.append(new_item) + else: + ret.append(Genre.objects.get(pk=genre['id'])) - def _parseGenreList(self, genres): - #for magic.. - ret = [] - for genre in genres: - if genre['id'] == genre['text']: - new_item = Genre(description=genre['text']) - new_item.save() - ret.append(new_item) - else: - ret.append(Genre.objects.get(pk=genre['id'])) + return ret - return ret + def _unpackGenreList(self, bundle, genres): + genre_list = self._parseGenreList(genres) + bundle.obj.genres = genre_list + bundle.obj.save() - def _unpackGenreList(self, bundle, genres): - genre_list = self._parseGenreList(genres) - bundle.obj.genres = genre_list - bundle.obj.save() + def prepend_urls(self): + return [ + url(r"^(?P%s)/search%s$" % (self._meta.resource_name, trailing_slash()), + self.wrap_view('get_search'), + name="api_get_search"), + url(r"^(?P%s)/(?P[\d]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), + name="api_dispatch_detail"), + url(r"^(?P%s)/random/$" % self._meta.resource_name, self.wrap_view('dispatch_random'), + name="api_dispatch_random"), + url(r"^(?P%s)/(?P[\w\d-]+)/$" % self._meta.resource_name, + self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), + url(r"^(?P%s)/(?P\w[\w/-]*)/comments%s$" % ( + self._meta.resource_name, trailing_slash()), self.wrap_view('get_comments'), name="api_get_comments"), + url(r"^(?P%s)/(?P\w[\w/-]*)/activity%s$" % ( + self._meta.resource_name, trailing_slash()), self.wrap_view('get_activity'), name="api_get_activity"), + ] - def prepend_urls(self): - return [ - url(r"^(?P%s)/search%s$" % (self._meta.resource_name, trailing_slash()), - self.wrap_view('get_search'), - name="api_get_search"), - url(r"^(?P%s)/(?P[\d]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), - name="api_dispatch_detail"), - url(r"^(?P%s)/random/$" % self._meta.resource_name, self.wrap_view('dispatch_random'), - name="api_dispatch_random"), - url(r"^(?P%s)/(?P[\w\d-]+)/$" % self._meta.resource_name, - self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), - url(r"^(?P%s)/(?P\w[\w/-]*)/comments%s$" % ( - self._meta.resource_name, trailing_slash()), self.wrap_view('get_comments'), name="api_get_comments"), - url(r"^(?P%s)/(?P\w[\w/-]*)/activity%s$" % ( - self._meta.resource_name, trailing_slash()), self.wrap_view('get_activity'), name="api_get_activity"), - ] + def dispatch_random(self, request, **kwargs): + kwargs['pk'] = self._meta.queryset.values_list('pk', flat=True).order_by('?')[0] + return self.get_detail(request, **kwargs) - def dispatch_random(self, request, **kwargs): - kwargs['pk'] = self._meta.queryset.values_list('pk', flat=True).order_by('?')[0] - return self.get_detail(request, **kwargs) + def get_comments(self, request, **kwargs): + try: + basic_bundle = self.build_bundle(request=request) + obj = self.cached_obj_get(bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) + except ObjectDoesNotExist: + return HttpGone() - def get_comments(self, request, **kwargs): - try: - basic_bundle = self.build_bundle(request=request) - obj = self.cached_obj_get(bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) - except ObjectDoesNotExist: - return HttpGone() + child_resource = CommentResource() + return child_resource.get_list(request, mix=obj) - child_resource = CommentResource() - return child_resource.get_list(request, mix=obj) + def get_activity(self, request, **kwargs): + try: + basic_bundle = self.build_bundle(request=request) + obj = self.cached_obj_get(bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) + except ObjectDoesNotExist: + return HttpGone() - def get_activity(self, request, **kwargs): - try: - basic_bundle = self.build_bundle(request=request) - obj = self.cached_obj_get(bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) - except ObjectDoesNotExist: - return HttpGone() + child_resource = ActivityResource() + return child_resource.get_list(request, mix=obj) - child_resource = ActivityResource() - return child_resource.get_list(request, mix=obj) + def obj_create(self, bundle, **kwargs): + file_name = "mixes/%s.%s" % (bundle.data['upload-hash'], bundle.data['upload-extension']) + uid = bundle.data['upload-hash'] + if 'is_featured' not in bundle.data: + bundle.data['is_featured'] = False - def obj_create(self, bundle, **kwargs): - file_name = "mixes/%s.%s" % (bundle.data['upload-hash'], bundle.data['upload-extension']) - uid = bundle.data['upload-hash'] - if 'is_featured' not in bundle.data: - bundle.data['is_featured'] = False + if 'download_allowed' not in bundle.data: + bundle.data['download_allowed'] = False - if 'download_allowed' not in bundle.data: - bundle.data['download_allowed'] = False + bundle.data['user'] = bundle.request.user.get_profile() + ret = super(MixResource, self).obj_create( + bundle, + user=bundle.request.user.get_profile(), + local_file=file_name, + uid=uid) - bundle.data['user'] = bundle.request.user.get_profile() - ret = super(MixResource, self).obj_create( - bundle, - user=bundle.request.user.get_profile(), - local_file=file_name, - uid=uid) + return ret - self._unpackGenreList(ret, bundle.data['genre-list']) - #if ret is hunky dory - return ret + def obj_update(self, bundle, **kwargs): + #don't sync the mix_image, this has to be handled separately + del bundle.data['mix_image'] + ret = super(MixResource, self).obj_update(bundle, bundle.request) - def obj_update(self, bundle, **kwargs): - #don't sync the mix_image, this has to be handled separately - del bundle.data['mix_image'] - ret = super(MixResource, self).obj_update(bundle, bundle.request) + bundle.obj.update_favourite(bundle.request.user, bundle.data['favourited']) + bundle.obj.update_liked(bundle.request.user, bundle.data['liked']) - bundle.obj.update_favourite(bundle.request.user, bundle.data['favourited']) - bundle.obj.update_liked(bundle.request.user, bundle.data['liked']) + return ret - self._unpackGenreList(ret, bundle.data['genre-list']) - return ret + def apply_sorting(self, obj_list, options=None): + orderby = options.get('order_by', '') + if orderby == 'latest': + obj_list = obj_list.order_by('-id') + elif orderby == 'toprated': + obj_list = obj_list.annotate(karma=Count('activity_likes')).order_by('-karma') + elif orderby == 'mostplayed': + obj_list = obj_list.annotate(karma=Count('activity_plays')).order_by('-karma') + elif orderby == 'mostactive': + obj_list = obj_list.annotate(karma=Count('comments')).order_by('-karma') + elif orderby == 'recommended': + obj_list = obj_list.annotate(karma=Count('activity_likes')).order_by('-karma') - def apply_sorting(self, obj_list, options=None): - orderby = options.get('order_by', '') - if orderby == 'latest': - obj_list = obj_list.order_by('-id') - elif orderby == 'toprated': - obj_list = obj_list.annotate(karma=Count('activity_likes')).order_by('-karma') - elif orderby == 'mostplayed': - obj_list = obj_list.annotate(karma=Count('activity_plays')).order_by('-karma') - elif orderby == 'mostactive': - obj_list = obj_list.annotate(karma=Count('comments')).order_by('-karma') - elif orderby == 'recommended': - obj_list = obj_list.annotate(karma=Count('activity_likes')).order_by('-karma') + return obj_list - return obj_list + def apply_filters(self, request, applicable_filters): + semi_filtered = super(MixResource, self) \ + .apply_filters(request, applicable_filters) \ + .filter(waveform_generated=True) - def apply_filters(self, request, applicable_filters): - semi_filtered = super(MixResource, self) \ - .apply_filters(request, applicable_filters) \ - .filter(waveform_generated=True) + f_user = request.GET.get('user', None) - f_user = request.GET.get('user', None) + if request.GET.get('stream'): + semi_filtered = semi_filtered.filter(user__in=request.user.get_profile().following.all()) + if f_user is not None: + semi_filtered = semi_filtered.filter(user__slug=f_user) + else: + semi_filtered = semi_filtered.filter(is_featured=True) - if request.GET.get('stream'): - semi_filtered = semi_filtered.filter(user__in=request.user.get_profile().following.all()) - if f_user is not None: - semi_filtered = semi_filtered.filter(user__slug=f_user) - else: - semi_filtered = semi_filtered.filter(is_featured=True) + return semi_filtered - return semi_filtered + def dehydrate_mix_image(self, bundle): + return bundle.obj.get_image_url(size="160x110") - def dehydrate_mix_image(self, bundle): - return bundle.obj.get_image_url(size="160x110") + def dehydrate(self, bundle): + bundle.data['waveform_url'] = bundle.obj.get_waveform_url() + bundle.data['user_name'] = bundle.obj.user.get_nice_name() + bundle.data['user_profile_url'] = bundle.obj.user.get_absolute_url() + bundle.data['user_profile_image'] = bundle.obj.user.get_small_profile_image() + bundle.data['item_url'] = '/mix/%s' % bundle.obj.slug + bundle.data['download_allowed'] = bundle.obj.download_allowed and \ + bundle.obj.upload_date < datetime.datetime.now() - datetime.timedelta(days=1) - def dehydrate(self, bundle): - bundle.data['waveform_url'] = bundle.obj.get_waveform_url() - bundle.data['user_name'] = bundle.obj.user.get_nice_name() - bundle.data['user_profile_url'] = bundle.obj.user.get_absolute_url() - bundle.data['user_profile_image'] = bundle.obj.user.get_small_profile_image() - bundle.data['item_url'] = '/mix/%s' % bundle.obj.slug - bundle.data['download_allowed'] = bundle.obj.download_allowed and \ - bundle.obj.upload_date < datetime.datetime.now() - datetime.timedelta(days=1) + bundle.data['favourite_count'] = bundle.obj.favourites.count() - bundle.data['favourite_count'] = bundle.obj.favourites.count() + bundle.data['play_count'] = bundle.obj.activity_plays.count() + bundle.data['download_count'] = bundle.obj.activity_downloads.count() + bundle.data['like_count'] = bundle.obj.activity_likes.count() - bundle.data['play_count'] = bundle.obj.activity_plays.count() - bundle.data['download_count'] = bundle.obj.activity_downloads.count() - bundle.data['like_count'] = bundle.obj.activity_likes.count() + bundle.data['tooltip'] = render_to_string('inc/player_tooltip.html', {'item': bundle.obj}) + bundle.data['comment_count'] = bundle.obj.comments.count() - bundle.data['tooltip'] = render_to_string('inc/player_tooltip.html', {'item': bundle.obj}) - bundle.data['comment_count'] = bundle.obj.comments.count() + #bundle.data['genre-list'] = json.to_ajax(bundle.obj.genres.all(), 'description', 'slug') + bundle.data['liked'] = bundle.obj.is_liked(bundle.request.user) - bundle.data['genre-list'] = json.to_ajax(bundle.obj.genres.all(), 'description', 'slug') - bundle.data['liked'] = bundle.obj.is_liked(bundle.request.user) + if bundle.request.user.is_authenticated(): + bundle.data['can_edit'] = bundle.request.user.is_staff or bundle.obj.user_id == bundle.request.user.id + else: + bundle.data['can_edit'] = False - if bundle.request.user.is_authenticated(): - bundle.data['can_edit'] = bundle.request.user.is_staff or bundle.obj.user_id == bundle.request.user.id - else: - bundle.data['can_edit'] = False + if bundle.request.user.is_authenticated(): + bundle.data['favourited'] = bundle.obj.favourites.filter(user=bundle.request.user).count() != 0 + else: + bundle.data['favourited'] = False - if bundle.request.user.is_authenticated(): - bundle.data['favourited'] = bundle.obj.favourites.filter(user=bundle.request.user).count() != 0 - else: - bundle.data['favourited'] = False + return bundle - return bundle - def get_search(self, request, **kwargs): - self.method_check(request, allowed=['get']) - self.is_authenticated(request) - self.throttle_check(request) + def get_search(self, request, **kwargs): + self.method_check(request, allowed=['get']) + self.is_authenticated(request) + self.throttle_check(request) - # Do the query. - sqs = Mix.objects.filter(title__icontains=request.GET.get('q', '')) - paginator = Paginator(sqs, 20) + # Do the query. + sqs = Mix.objects.filter(title__icontains=request.GET.get('q', '')) + paginator = Paginator(sqs, 20) - try: - page = paginator.page(int(request.GET.get('page', 1))) - except InvalidPage: - raise Http404("Sorry, no results on that page.") + try: + page = paginator.page(int(request.GET.get('page', 1))) + except InvalidPage: + raise Http404("Sorry, no results on that page.") - objects = [] + objects = [] - for result in page.object_list: - bundle = self.build_bundle(obj=result, request=request) - bundle = self.full_dehydrate(bundle) - objects.append(bundle) + for result in page.object_list: + bundle = self.build_bundle(obj=result, request=request) + bundle = self.full_dehydrate(bundle) + objects.append(bundle) - object_list = { - 'objects': objects, - } + object_list = { + 'objects': objects, + } - self.log_throttled_access(request) - return self.create_response(request, object_list) + self.log_throttled_access(request) + return self.create_response(request, object_list) diff --git a/static/js/app/views/comment/commentItemView.coffee b/static/js/app/views/comment/commentItemView.coffee index b14e258..836ed0a 100755 --- a/static/js/app/views/comment/commentItemView.coffee +++ b/static/js/app/views/comment/commentItemView.coffee @@ -7,6 +7,6 @@ define ['app.lib/dssView', 'utils', 'text!/tpl/CommentItemView'], } deleteComment: -> - utils.messageBox "/dlg/DeleteMixConfirm", => + utils.messageBox "/dlg/DeleteCommentConfirm", => @model.destroy() CommentItemView \ No newline at end of file diff --git a/static/js/app/views/comment/commentItemView.js b/static/js/app/views/comment/commentItemView.js index 666ab10..527cc4c 100755 --- a/static/js/app/views/comment/commentItemView.js +++ b/static/js/app/views/comment/commentItemView.js @@ -21,7 +21,7 @@ CommentItemView.prototype.deleteComment = function() { var _this = this; - return utils.messageBox("/dlg/DeleteMixConfirm", function() { + return utils.messageBox("/dlg/DeleteCommentConfirm", function() { return _this.model.destroy(); }); }; diff --git a/static/js/app/views/mix/mixEditView.coffee b/static/js/app/views/mix/mixEditView.coffee index fd3704f..f7ee05e 100755 --- a/static/js/app/views/mix/mixEditView.coffee +++ b/static/js/app/views/mix/mixEditView.coffee @@ -69,13 +69,12 @@ define ['app.lib/editableView', 'moment', 'utils', 'backbone.syphon', 'text!/tpl initSelection: (element, callback) -> console.log("MixEditView: genres:initSelection") result = [] - genres = parent.model.get("genre-list") + genres = parent.model.get("genres") unless genres is `undefined` $.each genres, (data) -> result.push id: @id - text: @text - + text: @description callback result @@ -94,7 +93,10 @@ define ['app.lib/editableView', 'moment', 'utils', 'backbone.syphon', 'text!/tpl @model.set data @model.set "upload-hash", @guid @model.set "upload-extension", $("#upload-extension", @el).val() - @model.set "genre-list", $("#genres", @el).select2("data") + + $.each $("#genres", @el).select2("data"), (i, item) => + @model.get("genres").add({description: item.text}); + @model.unset "mix_image" unless @sendImage @model.unset "comments" diff --git a/static/js/app/views/mix/mixEditView.js b/static/js/app/views/mix/mixEditView.js index b145597..1c1ff0e 100755 --- a/static/js/app/views/mix/mixEditView.js +++ b/static/js/app/views/mix/mixEditView.js @@ -102,12 +102,12 @@ var genres, result; console.log("MixEditView: genres:initSelection"); result = []; - genres = parent.model.get("genre-list"); + genres = parent.model.get("genres"); if (genres !== undefined) { $.each(genres, function(data) { return result.push({ id: this.id, - text: this.text + text: this.description }); }); } @@ -135,7 +135,11 @@ this.model.set(data); this.model.set("upload-hash", this.guid); this.model.set("upload-extension", $("#upload-extension", this.el).val()); - this.model.set("genre-list", $("#genres", this.el).select2("data")); + $.each($("#genres", this.el).select2("data"), function(i, item) { + return _this.model.get("genres").add({ + description: item.text + }); + }); if (!this.sendImage) { this.model.unset("mix_image"); } diff --git a/static/js/app/views/mix/mixItemView.coffee b/static/js/app/views/mix/mixItemView.coffee index 415424f..0e456aa 100755 --- a/static/js/app/views/mix/mixItemView.coffee +++ b/static/js/app/views/mix/mixItemView.coffee @@ -49,8 +49,8 @@ define ['moment', 'app', 'vent', 'marionette', 'utils', renderGenres: => el = @el - $.each @model.get("genre-list"), (data) -> - $("#genre-list", el).append '' + @text + '' + $.each @model.get("genres"), (data) -> + $("#genre-list", el).append '' + @description + '' true true @@ -106,7 +106,8 @@ define ['moment', 'app', 'vent', 'marionette', 'utils', mixDelete: -> console.log("MixItemView: mixDelete") - vent.trigger("mix:delete", @model) + utils.messageBox "/dlg/DeleteMixConfirm", => + @model.destroy() mixLike: -> console.log("MixItemView: likeMix") diff --git a/static/js/app/views/mix/mixItemView.js b/static/js/app/views/mix/mixItemView.js index bf4f8aa..8a68e29 100755 --- a/static/js/app/views/mix/mixItemView.js +++ b/static/js/app/views/mix/mixItemView.js @@ -73,8 +73,8 @@ MixItemView.prototype.renderGenres = function() { var el; el = this.el; - $.each(this.model.get("genre-list"), function(data) { - $("#genre-list", el).append('' + this.text + ''); + $.each(this.model.get("genres"), function(data) { + $("#genre-list", el).append('' + this.description + ''); return true; }); return true; @@ -125,8 +125,11 @@ }; MixItemView.prototype.mixDelete = function() { + var _this = this; console.log("MixItemView: mixDelete"); - return vent.trigger("mix:delete", this.model); + return utils.messageBox("/dlg/DeleteMixConfirm", function() { + return _this.model.destroy(); + }); }; MixItemView.prototype.mixLike = function() { diff --git a/static/js/com.podnoms.realtime.js b/static/js/com.podnoms.realtime.js index 1bb064f..4ca02aa 100755 --- a/static/js/com.podnoms.realtime.js +++ b/static/js/com.podnoms.realtime.js @@ -7,7 +7,6 @@ */ - /* var socket = new io.Socket({host: 'ext-test.deepsouthsounds.com', resource: 'socket.io', port: '8000', rememberTransport: false}); socket.connect(); @@ -37,4 +36,3 @@ function message (from, msg) { console.log(msg); $('#lines').append($('

').append($('').text(from), msg)); } -*/ \ No newline at end of file diff --git a/templates/views/_MixItemInsert.html b/templates/views/_MixItemInsert.html index 12acec4..fb6ab6a 100755 --- a/templates/views/_MixItemInsert.html +++ b/templates/views/_MixItemInsert.html @@ -79,14 +79,14 @@ {% if user.is_authenticated %}

{% endif %}