From 7f7375b7dbed5c325d3ee65cf8c6d53b5d1b7811 Mon Sep 17 00:00:00 2001 From: Ana Date: Thu, 11 Aug 2016 16:38:39 +0200 Subject: [PATCH 1/4] Introduce an association between User and Event Introduce an association between User and Event for the user schedule. As there was already a relation call users in Event the new relation is called public_users. And for the same reason the relation in Event is called public_events. --- app/models/event.rb | 3 +++ app/models/user.rb | 3 +++ db/migrate/20160811143427_create_events_users.rb | 8 ++++++++ db/schema.rb | 5 +++++ 4 files changed, 19 insertions(+) create mode 100644 db/migrate/20160811143427_create_events_users.rb diff --git a/app/models/event.rb b/app/models/event.rb index 1eebb0b0..63125f20 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -22,8 +22,11 @@ class Event < ActiveRecord::Base belongs_to :difficulty_level belongs_to :program + has_and_belongs_to_many :favourite_users, class_name: 'User' + accepts_nested_attributes_for :event_users, allow_destroy: true accepts_nested_attributes_for :users + accepts_nested_attributes_for :favourite_users before_create :generate_guid diff --git a/app/models/user.rb b/app/models/user.rb index 05edcce6..580e11e1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -49,6 +49,9 @@ class User < ActiveRecord::Base has_many :votes, dependent: :destroy has_many :voted_events, through: :votes, source: :events has_many :subscriptions, dependent: :destroy + + has_and_belongs_to_many :favourite_events, class_name: 'Event' + accepts_nested_attributes_for :roles scope :admin, -> { where(is_admin: true) } diff --git a/db/migrate/20160811143427_create_events_users.rb b/db/migrate/20160811143427_create_events_users.rb new file mode 100644 index 00000000..64a7fa6e --- /dev/null +++ b/db/migrate/20160811143427_create_events_users.rb @@ -0,0 +1,8 @@ +class CreateEventsUsers < ActiveRecord::Migration + def change + create_table :events_users, id: false do |t| + t.references :event + t.references :user + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 34c30a04..4ac79b13 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -243,6 +243,11 @@ ActiveRecord::Schema.define(version: 20170213145807) do t.datetime "created_at" end + create_table "events_users", id: false, force: :cascade do |t| + t.integer "event_id" + t.integer "user_id" + end + create_table "lodgings", force: :cascade do |t| t.string "name" t.text "description" From 9154f1883d6d53422bcfb7bbc9e38749d10a501c Mon Sep 17 00:00:00 2001 From: Ana Date: Fri, 12 Aug 2016 00:41:02 +0200 Subject: [PATCH 2/4] Make it possible to select favourites events Make it possible for users to select events which they want to see in the public schedule and in the All events section of the public schedule. --- app/assets/javascripts/osem-schedule.js | 30 +++++++++++++++++++ app/assets/stylesheets/osem-schedule.css.scss | 9 ++++++ app/controllers/proposals_controller.rb | 28 ++++++++++++----- app/views/schedules/_event.html.haml | 8 +++-- app/views/schedules/_schedule_item.html.haml | 9 +++++- 5 files changed, 74 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/osem-schedule.js b/app/assets/javascripts/osem-schedule.js index baae1933..41136871 100644 --- a/app/assets/javascripts/osem-schedule.js +++ b/app/assets/javascripts/osem-schedule.js @@ -1,3 +1,5 @@ +// ADMIN SCHEDULE + var url; // Should be initialize in Schedule.initialize var schedule_id; // Should be initialize in Schedule.initialize @@ -117,6 +119,34 @@ $(document).ready( function() { }); }); + +// PUBLIC SCHEDULE + +function starClicked(e){ + // stops the click from propagating + if (!e) var e = window.event; + e.preventDefault(); + e.cancelBubble = true; + if (e.stopPropagation) e.stopPropagation(); + + var callback = function(data) { + $(e.target).toggleClass('fa-star fa-star-o'); + } + + var params = { favourite_user_id: $(e.target).data('user') }; + if($(e.target).hasClass('fa-star-o')){ + params['add'] = true; + } + + $.ajax({ + url: $(e.target).data('url'), + type: 'PATCH', + data: params, + success: callback, + dataType : 'json' + }); +} + function eventClicked(e, element){ var url = $(element).data('url'); if(e.ctrlKey) diff --git a/app/assets/stylesheets/osem-schedule.css.scss b/app/assets/stylesheets/osem-schedule.css.scss index f2a97b83..c5b872f1 100644 --- a/app/assets/stylesheets/osem-schedule.css.scss +++ b/app/assets/stylesheets/osem-schedule.css.scss @@ -263,6 +263,15 @@ td.no-padding{ font-size: 7px; } +#star{ + margin-top: 8px; +} + +#star-events{ + margin-right: 5px; + vertical-align: text-top; +} + /* Small devices (tablets, 768px and up) */ @media (min-width: 768px) { .room, .event-title{ diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 3ef8bd5f..cb65364a 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -63,14 +63,28 @@ class ProposalsController < ApplicationController end def update - @url = conference_program_proposal_path(@conference.short_title, params[:id]) + respond_to do |format| + format.html do + @url = conference_program_proposal_path(@conference.short_title, params[:id]) - if @event.update(event_params) - redirect_to conference_program_proposals_path(conference_id: @conference.short_title), - notice: 'Proposal was successfully updated.' - else - flash[:error] = "Could not update proposal: #{@event.errors.full_messages.join(', ')}" - render action: 'edit' + if @event.update(event_params) + redirect_to conference_program_proposals_path(conference_id: @conference.short_title), + notice: 'Proposal was successfully updated.' + else + flash[:error] = "Could not update proposal: #{@event.errors.full_messages.join(', ')}" + render action: 'edit' + end + end + format.json do + user = User.find(params[:favourite_user_id]) + users = @event.favourite_users + if users.include? user + @event.favourite_users.delete(user) + else + @event.favourite_users << User.find(params[:favourite_user_id]) + end + render json: {} + end end end diff --git a/app/views/schedules/_event.html.haml b/app/views/schedules/_event.html.haml index 49116e42..c4bfadde 100644 --- a/app/views/schedules/_event.html.haml +++ b/app/views/schedules/_event.html.haml @@ -4,11 +4,15 @@ = image_tag speaker.gravatar_url, :class => "img-circle pull-right all-speaker-pic", | :alt => speaker.name, | :title => speaker.name | - %p = canceled_replacement_event_label(event, event_schedule) = replacement_event_notice(event_schedule) - + - if current_user + = link_to('#', onClick: 'starClicked();') do + %span#star-events{ class: "fa fa-lg #{ event.favourite_users.exists?(current_user.id) ? 'fa-star' : 'fa-star-o' }", | + "aria-hidden" => "true", | + "data-url" => conference_program_proposal_path(@conference.short_title, event.id), | + "data-user" => current_user.id } %span.h3 = event.title %br diff --git a/app/views/schedules/_schedule_item.html.haml b/app/views/schedules/_schedule_item.html.haml index ffed1716..74aeb64c 100644 --- a/app/views/schedules/_schedule_item.html.haml +++ b/app/views/schedules/_schedule_item.html.haml @@ -1,7 +1,7 @@ %td.event{ width: "#{ width * span }%" , | colspan: span, | role: "button" } - %a.unstyled-link{href: url_for(conference_program_proposal_path(@conference.short_title, event.id))} + %div{ onClick: 'eventClicked(event, this);', "data-url" => "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}" } %div{ class: "elipsis break-words event-title", | style: "-webkit-line-clamp: #{ event_lines(@rooms) }; height: #{ event_height(@rooms) }px;"} | @@ -9,6 +9,13 @@ = event.title + - if current_user + = link_to('#', onClick: 'starClicked();') do + %span#star{ class: "fa fa-lg #{ event.favourite_users.exists?(current_user.id) ? 'fa-star' : 'fa-star-o' }", | + "aria-hidden" =>"true", | + "data-url" => conference_program_proposal_path(@conference.short_title, event.id), | + "data-user" => current_user.id } + - if speaker = event.speakers.first = image_tag speaker.gravatar_url, :class => "img-circle pull-right speaker-pic", | :alt => speaker.name, | From f54df5922ed8ff37da3ee1b5d49cbc4661345c3d Mon Sep 17 00:00:00 2001 From: Ana Date: Sat, 13 Aug 2016 02:26:02 +0200 Subject: [PATCH 3/4] Show the individual User schedule Show the current user favourites events for both schedule and all events. Unsed css removed. --- app/assets/javascripts/osem-schedule.js | 3 --- app/assets/stylesheets/osem-schedule.css.scss | 20 +------------------ app/controllers/schedules_controller.rb | 8 ++++++++ app/views/schedules/_carousel.html.haml | 1 + app/views/schedules/_schedule_item.html.haml | 13 ++++++------ app/views/schedules/_schedule_tabs.html.haml | 4 ++-- app/views/schedules/events.html.haml | 7 +++++++ app/views/schedules/show.html.haml | 7 +++++++ 8 files changed, 32 insertions(+), 31 deletions(-) diff --git a/app/assets/javascripts/osem-schedule.js b/app/assets/javascripts/osem-schedule.js index 41136871..683735af 100644 --- a/app/assets/javascripts/osem-schedule.js +++ b/app/assets/javascripts/osem-schedule.js @@ -134,9 +134,6 @@ function starClicked(e){ } var params = { favourite_user_id: $(e.target).data('user') }; - if($(e.target).hasClass('fa-star-o')){ - params['add'] = true; - } $.ajax({ url: $(e.target).data('url'), diff --git a/app/assets/stylesheets/osem-schedule.css.scss b/app/assets/stylesheets/osem-schedule.css.scss index c5b872f1..3cab9cb7 100644 --- a/app/assets/stylesheets/osem-schedule.css.scss +++ b/app/assets/stylesheets/osem-schedule.css.scss @@ -127,7 +127,7 @@ a.unstyled-link { .program-dropdown, .schedule-dropdown{ margin-left: 20%; margin-right: 20%; - margin-top: 40px; + margin-top: 10px; margin-bottom: 20px; } @@ -234,20 +234,6 @@ td.no-padding{ cursor: pointer; } -.program-dropdown{ - margin-left: 20%; - margin-right: 20%; - margin-top: 40px; -} - -.program-dropdown > button{ - width: 100%; -} - -.program-dropdown > .dropdown-menu{ - width: 100%; -} - .no-events-day{ color: #D8D8D8 !important; } @@ -263,10 +249,6 @@ td.no-padding{ font-size: 7px; } -#star{ - margin-top: 8px; -} - #star-events{ margin-right: 5px; vertical-align: text-top; diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index 0b135328..8d6e37a1 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -1,6 +1,7 @@ class SchedulesController < ApplicationController protect_from_forgery with: :null_session before_action :respond_to_options + before_action :favourites load_and_authorize_resource :conference, find_by: :short_title load_resource :program, through: :conference, singleton: true, except: :index @@ -29,13 +30,16 @@ class SchedulesController < ApplicationController @dates = @conference.start_date..@conference.end_date @events_schedules = @program.selected_event_schedules + @events_schedules = @events_schedules.select{ |e| e.event.favourite_users.exists?(current_user.id) } if @events_schedules && current_user && @favourites @events_schedules = [] unless @events_schedules + @favourites = params[:favourites] == 'true' @unscheduled_events = if @program.selected_schedule @program.events.confirmed - @program.selected_schedule.events else @program.events.confirmed end + @unscheduled_events = @unscheduled_events.select{ |e| e.favourite_users.exists?(current_user.id) } if current_user && @favourites day = @conference.current_conference_day @tag = day.strftime('%Y-%m-%d') if day @@ -43,6 +47,10 @@ class SchedulesController < ApplicationController private + def favourites + @favourites = params[:favourites] == 'true' + end + def respond_to_options respond_to do |format| format.html { head :ok } diff --git a/app/views/schedules/_carousel.html.haml b/app/views/schedules/_carousel.html.haml index 5c5acc29..0bbab166 100644 --- a/app/views/schedules/_carousel.html.haml +++ b/app/views/schedules/_carousel.html.haml @@ -30,6 +30,7 @@ .room.elipsis.break-words{ style: "-webkit-line-clamp: #{ room_lines(@rooms) }; height: #{ room_height(@rooms) }px;" } = room.name - event_schedules = room.event_schedules.select{ |e| (e.schedule_id == @conference.program.selected_schedule.id) && (e.end_time > start_time) && (e.start_time <= (start_time + hrs_per_slide.hour)) } + - event_schedules = event_schedules.select{ |e| e.event.favourite_users.exists?(current_user.id) } if current_user && @favourites - (1..intervals).each do |i| - if span > 1 - span -= 1 diff --git a/app/views/schedules/_schedule_item.html.haml b/app/views/schedules/_schedule_item.html.haml index 74aeb64c..027cfcc4 100644 --- a/app/views/schedules/_schedule_item.html.haml +++ b/app/views/schedules/_schedule_item.html.haml @@ -7,15 +7,14 @@ = canceled_replacement_event_label(event, event_schedule, 'schedule-label') + - if current_user + = link_to('#', onClick: 'starClicked();') do + %span#star{ class: "fa fa-lg #{ event.favourite_users.exists?(current_user.id) ? 'fa-star' : 'fa-star-o' }", | + "aria-hidden" =>"true", | + "data-url" => conference_program_proposal_path(@conference.short_title, event.id), | + "data-user" => current_user.id } = event.title - - if current_user - = link_to('#', onClick: 'starClicked();') do - %span#star{ class: "fa fa-lg #{ event.favourite_users.exists?(current_user.id) ? 'fa-star' : 'fa-star-o' }", | - "aria-hidden" =>"true", | - "data-url" => conference_program_proposal_path(@conference.short_title, event.id), | - "data-user" => current_user.id } - - if speaker = event.speakers.first = image_tag speaker.gravatar_url, :class => "img-circle pull-right speaker-pic", | :alt => speaker.name, | diff --git a/app/views/schedules/_schedule_tabs.html.haml b/app/views/schedules/_schedule_tabs.html.haml index 0317f8bc..30dd5ab7 100644 --- a/app/views/schedules/_schedule_tabs.html.haml +++ b/app/views/schedules/_schedule_tabs.html.haml @@ -2,6 +2,6 @@ / Nav tabs %ul.nav.nav-tabs{ role: "tablist" } %li{ class: "schedule #{ 'active' if active == 'schedule' }", role: "presentation" } - = link_to('Schedule', conference_schedule_path(@conference.short_title)) + = link_to('Schedule', conference_schedule_path(@conference.short_title, favourites: @favourites)) %li{ class: "program #{ 'active' if active == 'program' }", role: "presentation" } - = link_to('All events', events_conference_schedule_path(@conference.short_title)) + = link_to('All events', events_conference_schedule_path(@conference.short_title, favourites: @favourites)) diff --git a/app/views/schedules/events.html.haml b/app/views/schedules/events.html.haml index 8680d3c3..b63cb184 100644 --- a/app/views/schedules/events.html.haml +++ b/app/views/schedules/events.html.haml @@ -5,6 +5,13 @@ %h1.text-center Program for = @conference.title + - if current_user + .row + .col-md-12.text-center + = button_to (@favourites ? 'All events' : 'Only favourites events'), + events_conference_schedule_path(@conference.short_title), + params: { favourites: !@favourites }, + method: :get, class: 'btn btn-success' .dropdown.program-dropdown %button{ type: "button", class: "btn btn-default dropdown-toggle", 'data-toggle' => "dropdown" } Dates diff --git a/app/views/schedules/show.html.haml b/app/views/schedules/show.html.haml index bd0f9976..d73a9107 100644 --- a/app/views/schedules/show.html.haml +++ b/app/views/schedules/show.html.haml @@ -5,6 +5,13 @@ %h1.text-center Schedule for = @conference.title + - if current_user + .row + .col-md-12.text-center + = button_to (@favourites ? 'All events' : 'Only favourites events'), + conference_schedule_path(@conference.short_title), + params: { favourites: !@favourites }, + method: :get, class: 'btn btn-success' .dropdown.schedule-dropdown %button{ type: "button", class: "btn btn-default dropdown-toggle", 'data-toggle' => "dropdown" } = @day From a907c1da5829c24fbe7efd4ce06aa50f81f688c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Sun, 19 Mar 2017 10:34:14 +0100 Subject: [PATCH 4/4] Move update favorites to a separate action Introduce a separate action `toggle_favorite` to update user favorites events. Otherwise users with permissions to update the event can have it as favorite. --- app/controllers/proposals_controller.rb | 42 ++++++++++---------- app/views/schedules/_event.html.haml | 2 +- app/views/schedules/_schedule_item.html.haml | 2 +- config/routes.rb | 1 + 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index cb65364a..9ed32c2f 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -1,10 +1,11 @@ class ProposalsController < ApplicationController + skip_authorization_check before_action :authenticate_user!, except: [:show, :new, :create] load_resource :conference, find_by: :short_title load_resource :program, through: :conference, singleton: true load_and_authorize_resource :event, parent: false, through: :program # We authorize manually in these actions - skip_authorize_resource :event, only: [:confirm, :restart, :withdraw] + skip_authorize_resource :event, only: [:confirm, :restart, :toogle_favorite, :withdraw] def index @event = @program.events.new @@ -63,31 +64,28 @@ class ProposalsController < ApplicationController end def update - respond_to do |format| - format.html do - @url = conference_program_proposal_path(@conference.short_title, params[:id]) + @url = conference_program_proposal_path(@conference.short_title, params[:id]) - if @event.update(event_params) - redirect_to conference_program_proposals_path(conference_id: @conference.short_title), - notice: 'Proposal was successfully updated.' - else - flash[:error] = "Could not update proposal: #{@event.errors.full_messages.join(', ')}" - render action: 'edit' - end - end - format.json do - user = User.find(params[:favourite_user_id]) - users = @event.favourite_users - if users.include? user - @event.favourite_users.delete(user) - else - @event.favourite_users << User.find(params[:favourite_user_id]) - end - render json: {} - end + if @event.update(event_params) + redirect_to conference_program_proposals_path(conference_id: @conference.short_title), + notice: 'Proposal was successfully updated.' + else + flash[:error] = "Could not update proposal: #{@event.errors.full_messages.join(', ')}" + render action: 'edit' end end + def toogle_favorite + user = User.find(params[:favourite_user_id]) + users = @event.favourite_users + if users.include? user + @event.favourite_users.delete(user) + else + @event.favourite_users << User.find(params[:favourite_user_id]) + end + render json: {} + end + def withdraw authorize! :update, @event @url = conference_program_proposal_path(@conference.short_title, params[:id]) diff --git a/app/views/schedules/_event.html.haml b/app/views/schedules/_event.html.haml index c4bfadde..7afcac48 100644 --- a/app/views/schedules/_event.html.haml +++ b/app/views/schedules/_event.html.haml @@ -11,7 +11,7 @@ = link_to('#', onClick: 'starClicked();') do %span#star-events{ class: "fa fa-lg #{ event.favourite_users.exists?(current_user.id) ? 'fa-star' : 'fa-star-o' }", | "aria-hidden" => "true", | - "data-url" => conference_program_proposal_path(@conference.short_title, event.id), | + "data-url" => toogle_favorite_conference_program_proposal_path(@conference.short_title, event.id), | "data-user" => current_user.id } %span.h3 = event.title diff --git a/app/views/schedules/_schedule_item.html.haml b/app/views/schedules/_schedule_item.html.haml index 027cfcc4..9d8ab42c 100644 --- a/app/views/schedules/_schedule_item.html.haml +++ b/app/views/schedules/_schedule_item.html.haml @@ -11,7 +11,7 @@ = link_to('#', onClick: 'starClicked();') do %span#star{ class: "fa fa-lg #{ event.favourite_users.exists?(current_user.id) ? 'fa-star' : 'fa-star-o' }", | "aria-hidden" =>"true", | - "data-url" => conference_program_proposal_path(@conference.short_title, event.id), | + "data-url" => toogle_favorite_conference_program_proposal_path(@conference.short_title, event.id), | "data-user" => current_user.id } = event.title diff --git a/config/routes.rb b/config/routes.rb index ba9228aa..64a3d522 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -115,6 +115,7 @@ Osem::Application.routes.draw do get :registrations patch '/confirm' => 'proposals#confirm' patch '/restart' => 'proposals#restart' + patch :toogle_favorite end end end