Adding favoriting to the schedule.

This commit is contained in:
Víðir Valberg Guðmundsson 2017-04-16 02:10:24 +02:00
parent 9f18d94ee1
commit 68aa108310
5 changed files with 103 additions and 9 deletions

View file

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import Event, Speaker, EventType, EventInstance, EventLocation, SpeakerProposal, EventProposal from .models import Event, Speaker, EventType, EventInstance, EventLocation, SpeakerProposal, EventProposal, Favorite
@admin.register(SpeakerProposal) @admin.register(SpeakerProposal)
@ -43,6 +43,11 @@ class SpeakerAdmin(admin.ModelAdmin):
pass pass
@admin.register(Favorite)
class FavoriteAdmin(admin.ModelAdmin):
raw_id_fields = ('event_instance',)
class SpeakerInline(admin.StackedInline): class SpeakerInline(admin.StackedInline):
model = Speaker.events.through model = Speaker.events.through

View file

@ -1,6 +1,6 @@
from channels.generic.websockets import JsonWebsocketConsumer from channels.generic.websockets import JsonWebsocketConsumer
from .models import EventInstance from .models import EventInstance, Favorite
class ScheduleConsumer(JsonWebsocketConsumer): class ScheduleConsumer(JsonWebsocketConsumer):
@ -12,7 +12,8 @@ class ScheduleConsumer(JsonWebsocketConsumer):
def connect(self, message, **kwargs): def connect(self, message, **kwargs):
self.send({"accept": True}) self.send({"accept": True})
def receive(self, content, **kwargs): def raw_receive(self, message, **kwargs):
content = self.decode_json(message['text'])
action = content.get('action') action = content.get('action')
data = {} data = {}
@ -20,7 +21,21 @@ class ScheduleConsumer(JsonWebsocketConsumer):
event_instance_id = content.get('event_instance_id') event_instance_id = content.get('event_instance_id')
event_instance = EventInstance.objects.get(id=event_instance_id) event_instance = EventInstance.objects.get(id=event_instance_id)
data['action'] = 'event_instance' data['action'] = 'event_instance'
data['event_instance'] = event_instance.to_json() data['event_instance'] = event_instance.to_json(user=message.user)
if action == 'favorite':
event_instance_id = content.get('event_instance_id')
event_instance = EventInstance.objects.get(id=event_instance_id)
Favorite.objects.create(
user=message.user,
event_instance=event_instance
)
if action == 'unfavorite':
event_instance_id = content.get('event_instance_id')
event_instance = EventInstance.objects.get(id=event_instance_id)
favorite = Favorite.objects.get(event_instance=event_instance, user=message.user)
favorite.delete()
self.send(data) self.send(data)

View file

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-04-15 23:21
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('program', '0037_eventtype_include_in_event_list'),
]
operations = [
migrations.CreateModel(
name='Favorite',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event_instance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='program.EventInstance')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorites', to=settings.AUTH_USER_MODEL)),
],
),
]

View file

@ -449,12 +449,13 @@ class EventInstance(CampRelatedModel):
ievent['location'] = icalendar.vText(self.location.name) ievent['location'] = icalendar.vText(self.location.name)
return ievent return ievent
def to_json(self): def to_json(self, user=None):
parser = CommonMark.Parser() parser = CommonMark.Parser()
renderer = CommonMark.HtmlRenderer() renderer = CommonMark.HtmlRenderer()
ast = parser.parse(self.event.abstract) ast = parser.parse(self.event.abstract)
abstract = renderer.render(ast) abstract = renderer.render(ast)
return {
data = {
'title': self.event.title, 'title': self.event.title,
'event_slug': self.event.slug, 'event_slug': self.event.slug,
'abstract': abstract, 'abstract': abstract,
@ -464,6 +465,12 @@ class EventInstance(CampRelatedModel):
'id': self.id, 'id': self.id,
} }
if user:
is_favorited = user.favorites.filter(event_instance=self).exists()
data['is_favorited'] = is_favorited
return data
def get_speaker_picture_upload_path(instance, filename): def get_speaker_picture_upload_path(instance, filename):
@ -543,3 +550,10 @@ class Speaker(CampRelatedModel):
return reverse_lazy('speaker_detail', kwargs={'camp_slug': self.camp.slug, 'slug': self.slug}) return reverse_lazy('speaker_detail', kwargs={'camp_slug': self.camp.slug, 'slug': self.slug})
class Favorite(models.Model):
user = models.ForeignKey('auth.User', related_name='favorites')
event_instance = models.ForeignKey('program.EventInstance')
class Meta:
unique_together = ['user', 'event_instance']

View file

@ -38,7 +38,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal">Close</button> <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Close</button>
<a class="btn btn-success"><i class="fa fa-star"></i> Favorite</a> <a class="favorite-button btn btn-success"><i class="fa fa-star"></i> Favorite</a>
<a class="more-button btn btn-info" href=""><i class="fa fa-info"></i> More</a> <a class="more-button btn btn-info" href=""><i class="fa fa-info"></i> More</a>
</div> </div>
</div> </div>
@ -58,7 +58,31 @@
var event_elements = document.getElementsByClassName("event"); var event_elements = document.getElementsByClassName("event");
var modals = {}; var modals = {};
var events = {};
function toggleFavoriteButton(button) {
if(button.getAttribute('data-state') == 'true') {
favorite_button.classList.remove('btn-success');
favorite_button.classList.add('btn-danger');
favorite_button.innerHTML = '<i class="fa fa-minus"></i> Remove favorite';
favorite_button.onclick = function(e) {
button.setAttribute('data-state', 'false')
webSocketBridge.send({action: 'unfavorite', event_instance_id: event_instance_id});
toggleFavoriteButton(button)
}
} else {
favorite_button.classList.remove('btn-danger');
favorite_button.classList.add('btn-success');
favorite_button.innerHTML = '<i class="fa fa-star"></i> Favorite';
favorite_button.onclick = function(e) {
button.setAttribute('data-state', 'true')
webSocketBridge.send({action: 'favorite', event_instance_id: event_instance_id});
toggleFavoriteButton(button)
}
}
}
webSocketBridge.connect('/schedule/'); webSocketBridge.connect('/schedule/');
webSocketBridge.socket.addEventListener('open', function() { webSocketBridge.socket.addEventListener('open', function() {
@ -74,12 +98,22 @@
modal_body.innerHTML = payload['event_instance']['abstract']; modal_body.innerHTML = payload['event_instance']['abstract'];
more_button = modal.getElementsByClassName('more-button')[0]; more_button = modal.getElementsByClassName('more-button')[0];
more_button.setAttribute('href', payload['event_instance']['url']); more_button.setAttribute('href', payload['event_instance']['url']);
favorite_button = modal.getElementsByClassName('favorite-button')[0];
favorite_button.setAttribute('data-state', payload['event_instance']['is_favorited'])
toggleFavoriteButton(favorite_button)
} }
}); });
function openModal(e) { function openModal(e) {
e.preventDefault(); e.preventDefault();
event_instance_id = e.target.dataset['eventinstanceId'];
// Avoid that clicking the text in the event will bring up an empty modal
target = e.target;
if (e.target !== this) {
target = e.target.parentElement
}
event_instance_id = target.dataset['eventinstanceId'];
modal = modals[event_instance_id]; modal = modals[event_instance_id];