From a8b94c13f37fdf48553170b5108ebf7325240d18 Mon Sep 17 00:00:00 2001 From: Chrisbr Date: Thu, 7 Aug 2014 21:33:08 +0200 Subject: [PATCH 1/2] Refactoring Conference Basics #384 --- app/assets/stylesheets/osem.css.scss | 49 ++++++++++++++- .../admin/conference_controller.rb | 5 +- app/controllers/admin/contacts_controller.rb | 39 +++++------- .../admin/conference/_edit_form.html.haml | 32 ++++++++++ .../admin/conference/_edit_show.html.haml | 61 +++++++++++++++++++ app/views/admin/conference/edit.html.haml | 49 +++++---------- app/views/admin/contacts/_form.html.haml | 44 ++++--------- app/views/admin/contacts/_show.html.haml | 31 ++++++++++ app/views/admin/contacts/edit.html.haml | 21 +++++-- app/views/layouts/_admin_sidebar.html.haml | 26 ++++---- config/routes.rb | 2 +- spec/features/conference_spec.rb | 9 +++ spec/features/contact_spec.rb | 50 +++++++++++++++ 13 files changed, 309 insertions(+), 109 deletions(-) create mode 100644 app/views/admin/conference/_edit_form.html.haml create mode 100644 app/views/admin/conference/_edit_show.html.haml create mode 100644 app/views/admin/contacts/_show.html.haml create mode 100644 spec/features/contact_spec.rb diff --git a/app/assets/stylesheets/osem.css.scss b/app/assets/stylesheets/osem.css.scss index d64a4776..4c4353c0 100644 --- a/app/assets/stylesheets/osem.css.scss +++ b/app/assets/stylesheets/osem.css.scss @@ -120,4 +120,51 @@ body { .pad{ padding-top: 35px; padding-bottom: 35px; -} \ No newline at end of file +} + +.dl-horizontal dt { white-space: normal; } + +.equal, .equal > div[class*='col-'] { + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + flex:1 0 auto; +} + +.row-flex, .row-flex > div[class*='col-'] { + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + flex:1 1 auto; +} + +.row-flex-wrap { + -webkit-flex-flow: row wrap; + align-content: flex-start; + flex:0; +} + +.row-flex > div[class*='col-'], .container-flex > div[class*='col-'] { + margin:-.2px; /* hack adjust for wrapping */ +} + +.container-flex > div[class*='col-'] div,.row-flex > div[class*='col-'] div { + width:100%; +} + +.flex-col { + display: flex; + display: -webkit-flex; + flex: 1 100%; + flex-flow: column nowrap; +} + +.flex-grow { + display: flex; + -webkit-flex: 2; + flex: 2; +} diff --git a/app/controllers/admin/conference_controller.rb b/app/controllers/admin/conference_controller.rb index 1f3ba8ee..4d8ffb40 100644 --- a/app/controllers/admin/conference_controller.rb +++ b/app/controllers/admin/conference_controller.rb @@ -20,7 +20,7 @@ module Admin @active_conferences = Conference.get_active_conferences_for_dashboard # pending or the last two @deactive_conferences = Conference. - get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active + get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active @conferences = @active_conferences + @deactive_conferences @recent_users = User.limit(5).order(created_at: :desc) @@ -116,7 +116,7 @@ module Admin @conference_progress = @conference.get_status # Line charts - @registrations = { @conference.short_title => @conference.get_registrations_per_week } + @registrations = {@conference.short_title => @conference.get_registrations_per_week} @registration_weeks = [0] @registration_weeks.push(@registrations[@conference.short_title].length) @@ -168,6 +168,7 @@ module Admin def edit @conferences = Conference.all @conference = Conference.find_by(short_title: params[:id]) + @date_string = date_string(@conference.start_date, @conference.end_date) respond_to do |format| format.html format.json { render json: @conference.to_json } diff --git a/app/controllers/admin/contacts_controller.rb b/app/controllers/admin/contacts_controller.rb index 39ee2108..6d97db98 100644 --- a/app/controllers/admin/contacts_controller.rb +++ b/app/controllers/admin/contacts_controller.rb @@ -1,11 +1,8 @@ module Admin class ContactsController < ApplicationController before_action :set_conference - before_action :set_contact, only: [:show, :edit, :update, :destroy] - - # GET /:conference/contact - def show - end + before_action :set_conference + before_action :set_contact, only: [:edit, :update] # GET /:conference/contact/edit def edit @@ -14,33 +11,27 @@ module Admin # PATCH/PUT /:conference/contact def update if @contact.update(contact_params) - redirect_to admin_conference_contact_path, notice: 'Contact details were successfully updated.' + redirect_to edit_admin_conference_contact_path, notice: 'Contact details were successfully updated.' else render :edit end end - # DELETE /:conference/contact - def destroy - @contact.destroy - redirect_to admin_conference_contacts_url, notice: 'Contact details were successfully destroyed.' - end - private - # Use callbacks to share common setup or constraints between actions. - def set_contact - @contact = @conference.contact - end + # Use callbacks to share common setup or constraints between actions. + def set_contact + @contact = @conference.contact + end - def set_conference - @conference = Conference.find_by(short_title: params[:conference_id]) - end + def set_conference + @conference = Conference.find_by(short_title: params[:conference_id]) + end - # Only allow a trusted parameter "white list" through. - def contact_params - # params.require(:contact).permit(:social_tag, :email, :facebook, :googleplus, :twitter, :instagram, :public) - params[:contact] - end + # Only allow a trusted parameter "white list" through. + def contact_params + # params.require(:contact).permit(:social_tag, :email, :facebook, :googleplus, :twitter, :instagram, :public) + params[:contact] + end end end diff --git a/app/views/admin/conference/_edit_form.html.haml b/app/views/admin/conference/_edit_form.html.haml new file mode 100644 index 00000000..11e7a513 --- /dev/null +++ b/app/views/admin/conference/_edit_form.html.haml @@ -0,0 +1,32 @@ +.row + .col-md-8 + = semantic_form_for(@conference, :url => admin_conference_path(@conference.short_title),:html => {:multipart => true}) do |f| + = f.input :make_conference_public, hint: 'This will enable the visitors to view the splash page(the "View Conference" button will be visible now on the home page), it is recommended to enable this after you have finished setting up all the components for display' + = f.input :include_program_in_splash, hint: 'On setting this true you will enable the program component to be displayed on the splash page.This component includes tracks, keynote speakers and the schedule' + = f.input :title, :hint => "The full name of the conference, such as 'OpenSUSE Conference 2013'" + = f.input :short_title, :hint => "A short title, such as 'osc2013', to be used in URLs" + = f.input :color, :hint => "The color will be used eg for the dashboard.", :input_html => {:size => 6, :type => "color"} + - if !@conference.logo.blank? + = image_tag @conference.logo(:thumb) + = f.input :logo, :label => "Conference Logo", :hint => "This will be displayed on the front page." + = f.inputs name: 'Banner for Splash' do + = f.input :include_banner_in_splash, hint: 'This enable the Banner Photo with description to be displayed on the splash' + = f.input :banner_photo, hint: 'This will be the top most component of the splash.This background cover will contain start_date and end_date of the conference and the description' + = f.input :description, hint: markdown_hint("This description will be shown at the bottom of the banner photo of the Splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } + + = f.inputs :name => "Scheduling" do + = f.input :timezone, :as => :time_zone, :hint => "The conference time zone" + = f.input :start_date, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" } + = f.input :end_date, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" } + = f.inputs name: 'Registration' do + = f.input :include_registrations_in_splash, hint: 'On setting this true you will enable the registrations to be displayed on the splash page' + = f.input :registration_start_date, :as => :string, :input_html => { :id => "conference-reg-start-datepicker", :readonly => "readonly" } + = f.input :registration_end_date, :as => :string, :input_html => { :id => "conference-reg-end-datepicker", :readonly => "readonly" } + = f.input :registration_description, hint: markdown_hint("This description will appear in registration segment of the splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } + = f.input :ticket_description, hint: markdown_hint("This will appear in the Tickets segment of the splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } + = f.input :sponsor_description, hint: markdown_hint("This will appear in the sponsor segment of the splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } + = f.input :sponsor_email, hint: 'This will appear in the sponsor segment of the splash for the sponsors to contact to the organizers' + = f.input :lodging_description, hint: markdown_hint("This will appear in the lodging segment of the splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } + + = dynamic_association :photos, "Photos", f + = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} diff --git a/app/views/admin/conference/_edit_show.html.haml b/app/views/admin/conference/_edit_show.html.haml new file mode 100644 index 00000000..ab08dbca --- /dev/null +++ b/app/views/admin/conference/_edit_show.html.haml @@ -0,0 +1,61 @@ +.row{'style'=>'padding-top: 15px;'} + .col-md-6 + %dl.dl-horizontal + %dt + Title + %dd + = @conference.title + %dt + Short Title + %dd + = @conference.short_title + %dt + Description + %dd + - unless @conference.description.blank? + = markdown(@conference.description) + - else + Not set! + %dt + Date + %dd + = @date_string + %dt + Color + %dd + %div.text-center{'style'=>"width: 25px; height: 25px; background: #{@conference.color};"} +.row.row-flex.row-flex-wrap + .col-md-4 + .thumbnail.flex-col + %h3.text-center + Conference Logo + - if @conference.logo? + = image_tag(@conference.logo(:large), class: 'img-responsive') + .caption.flex-grow + .caption + %p + %dl.dl-horizontal + %dt + Filename + %dd + = @conference.logo_file_name + -else + %h4.text-center + Not set! + .col-md-4 + .thumbnail.flex-col + %h3.text-center + Conference Banner + - if @conference.banner_photo? + = image_tag(@conference.banner_photo(:large), class: 'img-responsive') + .caption.flex-grow + .caption + %p + %dl.dl-horizontal + %dt + Filename + %dd + = @conference.banner_photo_file_name + - else + %h4.text-center + Not set! diff --git a/app/views/admin/conference/edit.html.haml b/app/views/admin/conference/edit.html.haml index 64148977..5eead37d 100644 --- a/app/views/admin/conference/edit.html.haml +++ b/app/views/admin/conference/edit.html.haml @@ -1,35 +1,16 @@ .row - .col-md-8 - = semantic_form_for(@conference, :url => admin_conference_path(@conference.short_title),:html => {:multipart => true}) do |f| - - = f.input :make_conference_public, hint: 'This will enable the visitors to view the splash page(the "View Conference" button will be visible now on the home page), it is recommended to enable this after you have finished setting up all the components for display' - = f.input :include_program_in_splash, hint: 'On setting this true you will enable the program component to be displayed on the splash page.This component includes tracks, keynote speakers and the schedule' - = f.input :title, :hint => "The full name of the conference, such as 'OpenSUSE Conference 2013'" - = f.input :short_title, :hint => "A short title, such as 'osc2013', to be used in URLs" - = f.input :color, :hint => "The color will be used eg for the dashboard.", :input_html => {:size => 6, :type => "color"} - = f.inputs name: 'Banner for Splash' do - = f.input :include_banner_in_splash, hint: 'This enable the Banner Photo with description to be displayed on the splash' - = f.input :banner_photo, hint: 'This will be the top most component of the splash.This background cover will contain start_date and end_date of the conference and the description' - = f.input :description, hint: markdown_hint("This description will be shown at the bottom of the banner photo of the Splash."), input_html: { data: { provide: "markdown-editable" } } - - = f.inputs :name => "Scheduling" do - = f.input :timezone, :as => :time_zone, :hint => "The conference time zone" - = f.input :start_date, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" } - = f.input :end_date, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" } - = f.inputs name: 'Registration' do - = f.input :include_registrations_in_splash, hint: 'On setting this true you will enable the registrations to be displayed on the splash page' - = f.input :registration_start_date, :as => :string, :input_html => { :id => "conference-reg-start-datepicker", :readonly => "readonly" } - = f.input :registration_end_date, :as => :string, :input_html => { :id => "conference-reg-end-datepicker", :readonly => "readonly" } - = f.input :registration_description, hint: markdown_hint("This description will appear in registration segment of the splash."), input_html: { data: { provide: "markdown-editable" } } - = f.input :ticket_description, hint: markdown_hint("This will appear in the Tickets segment of the splash."), input_html: { data: { provide: "markdown-editable" } } - = f.input :sponsor_description, hint: markdown_hint("This will appear in the sponsor segment of the splash."), input_html: { data: { provide: "markdown-editable" } } - = f.input :sponsor_email, hint: 'This will appear in the sponsor segment of the splash for the sponsors to contact to the organizers' - = f.input :lodging_description, hint: markdown_hint("This will appear in the lodging segment of the splash."), input_html: { data: { provide: "markdown-editable" } } - - = dynamic_association :photos, "Photos", f - - = f.inputs :name => 'Social Media' do - - if !@conference.logo.blank? - = image_tag @conference.logo(:thumb) - = f.input :logo, :label => "Conference Logo", :hint => "This will be displayed on the front page." - = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} + .col-md-12 + %ul.nav.nav-tabs{'role'=>'tablist'} + %li.active + %a{'href'=> '#show', 'role'=>'tab', 'data-toggle'=>'tab'} + Show + %li + %a{'href'=> '#edit', 'role'=>'tab', 'data-toggle'=>'tab'} + Edit +.row + .col-md-12 + .tab-content + .tab-pane.active#show + = render partial: 'edit_show' + .tab-pane#edit + = render partial: 'edit_form' \ No newline at end of file diff --git a/app/views/admin/contacts/_form.html.haml b/app/views/admin/contacts/_form.html.haml index 8113ebd3..2963b9b9 100644 --- a/app/views/admin/contacts/_form.html.haml +++ b/app/views/admin/contacts/_form.html.haml @@ -1,31 +1,13 @@ -= form_for @contact, url: admin_conference_contact_path do |f| - - if @contact.errors.any? - #error_explanation - %h2= "#{pluralize(@contact.errors.count, "error")} prohibited this contact from being saved:" - %ul - - @contact.errors.full_messages.each do |msg| - %li= msg - - .field - = f.label :social_tag - = f.text_field :social_tag - .field - = f.label :email - = f.text_field :email - .field - = f.label :facebook - = f.text_field :facebook - .field - = f.label :googleplus - = f.text_field :googleplus - .field - = f.label :twitter - = f.text_field :twitter - .field - = f.label :instagram - = f.text_field :instagram - .field - = f.label :public - = f.check_box :public - .actions - = f.submit 'Save' +.row + .col-md-8 + = semantic_form_for(@contact, :url => admin_conference_contact_path(@conference.short_title),:html => {:multipart => true}) do |f| + = f.inputs :name => 'Contact' do + = f.input :email, hint: 'Contact email address for your conference. Will be used as reply-to address in emails sent out by the system.' + = f.inputs :name => 'Social Media' do + = f.input :social_tag, hint: "The hashtag you'll use on Twitter and Google+. Don't include the '#' sign!'" + = f.input :facebook, hint: 'This will appear in the social media section as link to the Facebook page of your Conference' + = f.input :googleplus, label: 'Google+ Url', hint: 'This will appear in the social media section as the link to the Google+ Page of your Conference' + = f.input :twitter, hint: 'This will appear in the social media section as the link to the Twitter Page of your Conference' + = f.input :instagram, hint: 'This will appear in the social media section as the link to the Instagram Page of your Conference' + = f.input :public, hint: 'On setting this true you will enable the social media links to be displayed on the splash page' + = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/contacts/_show.html.haml b/app/views/admin/contacts/_show.html.haml new file mode 100644 index 00000000..71b4929f --- /dev/null +++ b/app/views/admin/contacts/_show.html.haml @@ -0,0 +1,31 @@ +%ul.list-unstyled + - unless @contact.email.blank? + %li + = link_to "#{ @contact.email }" do + %i.fa.fa-envelope.fa-3x + = @contact.email + - unless @contact.social_tag.blank? + %li + = link_to "#{ @contact.social_tag }" do + %i.fa.fa-thumbs-o-up.fa-3x + = "##{@contact.social_tag}" + - unless @contact.facebook.blank? + %li + = link_to "#{ @contact.facebook }" do + %i.fa.fa-facebook-square.fa-3x + = @contact.facebook + - unless @contact.twitter.blank? + %li + = link_to "#{ @contact.twitter }" do + %i.fa.fa-twitter.fa-3x + = @contact.twitter + - unless @contact.instagram.blank? + %li + = link_to "#{ @contact.instagram }" do + %i.fa.fa-instagram.fa-3x + = @contact.instagram + - unless @contact.googleplus.blank? + %li + = link_to "#{ @contact.googleplus }" do + %i.fa.fa-google.fa-3x + = @contact.googleplus \ No newline at end of file diff --git a/app/views/admin/contacts/edit.html.haml b/app/views/admin/contacts/edit.html.haml index f3dc61f9..b0adb5d0 100644 --- a/app/views/admin/contacts/edit.html.haml +++ b/app/views/admin/contacts/edit.html.haml @@ -1,5 +1,16 @@ -%h1 Editing contact - -= render 'form' - -= link_to 'Back', admin_conference_contact_path +.row + .col-md-12 + %ul.nav.nav-tabs{'role'=>'tablist'} + %li.active + %a{'href'=> '#show', 'role'=>'tab', 'data-toggle'=>'tab'} + Show + %li + %a{'href'=> '#edit', 'role'=>'tab', 'data-toggle'=>'tab'} + Edit +.row + .col-md-12 + .tab-content + .tab-pane.active#show + = render partial: 'show' + .tab-pane#edit + = render partial: 'form' \ No newline at end of file diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index 629e57e3..b9f5e5db 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -19,16 +19,24 @@ = link_to(new_admin_conference_path) do %span.glyphicon.glyphicon-plus New Conference - %hr - %li{:class=> active_nav_li(admin_conference_commercials_path(@conference.short_title))} - = link_to(admin_conference_commercials_path(@conference.short_title)) do - %span.fa.fa-picture-o - Commercials %hr %li{:class=> "#{active_nav_li(admin_conference_path(@conference.short_title))} nav-header nav-header-bigger"} = link_to(admin_conference_path(@conference.short_title)) do - %span.glyphicon.glyphicon-dashboard - Manage + %span.fa.fa-tachometer + Dashboard + %li{:class=> "#{active_nav_li(edit_admin_conference_path(@conference.short_title))}"} + = link_to(edit_admin_conference_path(@conference.short_title)) do + %span.fa.fa-home + Basics + %ul + %li{:class=> "#{active_nav_li(edit_admin_conference_contact_path(@conference.short_title))}"} + = link_to(edit_admin_conference_contact_path(@conference.short_title)) do + %span.fa.fa-envelope-o + Contact + %li{:class=> "#{active_nav_li(admin_conference_commercials_path(@conference.short_title))}"} + = link_to(admin_conference_commercials_path(@conference.short_title)) do + %span.fa.fa-comment + Commercials %li{:class=> active_nav_li(admin_conference_events_path(@conference.short_title))} = link_to(admin_conference_events_path(@conference.short_title)) do %span.glyphicon.glyphicon-comment @@ -46,10 +54,6 @@ %span.glyphicon.glyphicon-bullhorn Campaigns %hr - %li{:class=> "#{active_nav_li(edit_admin_conference_path(@conference.short_title))} nav-header nav-header-bigger"} - = link_to(edit_admin_conference_path(@conference.short_title)) do - %span.glyphicon.glyphicon-cog - Settings %li{:class=> "#{active_nav_li(admin_conference_targets_path(@conference.short_title))}"} = link_to(admin_conference_targets_path(@conference.short_title)) do %span.glyphicon.glyphicon-flag diff --git a/config/routes.rb b/config/routes.rb index 042b418b..c8bc7a05 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,7 +8,7 @@ Osem::Application.routes.draw do resources :users resources :people resources :conference do - resource :contact, except: [:index, :new, :create] + resource :contact, except: [:index, :new, :create, :show, :destroy] resource :schedule, only: [:show, :update] resources :commercials, except: [:show] get '/stats' => 'stats#index' diff --git a/spec/features/conference_spec.rb b/spec/features/conference_spec.rb index 4476044d..feed1eb8 100644 --- a/spec/features/conference_spec.rb +++ b/spec/features/conference_spec.rb @@ -39,6 +39,15 @@ feature Conference do sign_in create(user) visit edit_admin_conference_path(conference.short_title) + click_link 'Edit' + fill_in 'conference_title', with: 'New Con' + fill_in 'conference_short_title', with: '' + + click_button 'Update Conference' + expect(flash). + to eq("Updating conference failed. Short title can't be blank.") + + click_link 'Edit' fill_in 'conference_title', with: 'New Con' fill_in 'conference_short_title', with: 'NewCon' diff --git a/spec/features/contact_spec.rb b/spec/features/contact_spec.rb new file mode 100644 index 00000000..2a7bff79 --- /dev/null +++ b/spec/features/contact_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +feature Contact do + + # It is necessary to use bang version of let to build roles before user + let!(:organizer_role) { create(:organizer_role) } + let!(:participant_role) { create(:participant_role) } + let!(:admin_role) { create(:admin_role) } + + shared_examples 'update a contact' do |user| + + scenario 'sucessfully', feature: true, js: true do + conference = create(:conference) + contact = conference.contact + expected_count = Contact.count + sign_in create(user) + + visit edit_admin_conference_contact_path(conference.short_title) + click_link 'Edit' + fill_in 'contact_email', with: 'example@example.com' + fill_in 'contact_social_tag', with: 'example' + fill_in 'contact_facebook', with: 'http:\\www.facebook.com' + fill_in 'contact_twitter', with: 'http:\\www.twitter.com' + fill_in 'contact_instagram', with: 'http:\\www.instagram.com' + fill_in 'contact_googleplus', with: 'http:\\www.google.com' + + click_button 'Update Contact' + expect(flash). + to eq('Contact details were successfully updated.') + + contact.reload + expect(contact.email).to eq('example@example.com') + expect(contact.social_tag).to eq('example') + expect(contact.facebook).to eq('http:\\www.facebook.com') + expect(contact.twitter).to eq('http:\\www.twitter.com') + expect(contact.instagram).to eq('http:\\www.instagram.com') + expect(contact.googleplus).to eq('http:\\www.google.com') + expect(Contact.count).to eq(expected_count) + end + end + + describe 'admin' do + it_behaves_like 'update a contact', :admin + end + + describe 'organizer' do + it_behaves_like 'update a contact', :organizer + end + +end From 22cc5e4f142bc4e3c871a51271abd6b94015ad28 Mon Sep 17 00:00:00 2001 From: Chrisbr Date: Tue, 12 Aug 2014 08:38:51 +0200 Subject: [PATCH 2/2] Extracting Photos form Conference edit form close #384 --- app/controllers/admin/photos_controller.rb | 65 ++++++++++++++++ .../admin/conference/_edit_form.html.haml | 2 - .../admin/conference/_photo_fields.html.erb | 10 --- app/views/admin/photos/_form.html.haml | 7 ++ app/views/admin/photos/edit.html.haml | 6 ++ app/views/admin/photos/index.html.haml | 22 ++++++ app/views/admin/photos/new.html.haml | 6 ++ app/views/layouts/_admin_sidebar.html.haml | 6 +- config/routes.rb | 1 + spec/factories/photos.rb | 2 + spec/features/photo_spec.rb | 75 +++++++++++++++++++ spec/fixtures/test.txt | 1 + 12 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 app/controllers/admin/photos_controller.rb delete mode 100644 app/views/admin/conference/_photo_fields.html.erb create mode 100644 app/views/admin/photos/_form.html.haml create mode 100644 app/views/admin/photos/edit.html.haml create mode 100644 app/views/admin/photos/index.html.haml create mode 100644 app/views/admin/photos/new.html.haml create mode 100644 spec/features/photo_spec.rb create mode 100644 spec/fixtures/test.txt diff --git a/app/controllers/admin/photos_controller.rb b/app/controllers/admin/photos_controller.rb new file mode 100644 index 00000000..fc598d09 --- /dev/null +++ b/app/controllers/admin/photos_controller.rb @@ -0,0 +1,65 @@ +module Admin + class PhotosController < ApplicationController + before_action :set_conference + before_action :set_photo, only: [:edit, :update, :destroy] + +# GET /admin/photos + def index + @photos = @conference.photos.all + end + +# GET /admin/photos/new + def new + @photo = @conference.photos.build + end + +# GET /admin/photos/1/edit + def edit + end + +# POST /admin/photos + def create + @photo = @conference.photos.build(photo_params) + if @photo.save + redirect_to admin_conference_photos_path, notice: 'Photo was successfully created.' + else + flash[:alert] = "A error prohibited this Photo from being saved: #{@photo.errors.full_messages.join('. ')}." + render :new + end + end + +# PATCH/PUT /admin/photos/1 + def update + if @photo.update(photo_params) + redirect_to admin_conference_photos_path, notice: 'Photo was successfully updated.' + else + flash[:alert] = "A error prohibited this Photo from being saved: #{@photo.errors.full_messages.join('. ')}." + render :edit + end + end + +# DELETE /admin/photos/1 + def destroy + @photo.destroy + redirect_to admin_conference_photos_path, notice: 'Photo was successfully destroyed.' + end + + private + +# Use callbacks to share common setup or constraints between actions. + def set_conference + @conference = Conference.find_by(short_title: params[:conference_id]) + end + +# Use callbacks to share common setup or constraints between actions. + def set_photo + @photo = Photo.find_by(id: params[:id]) + end + +# Only allow a trusted parameter "white list" through. + def photo_params + params[:photo] + end + end +end + diff --git a/app/views/admin/conference/_edit_form.html.haml b/app/views/admin/conference/_edit_form.html.haml index 11e7a513..ed26829b 100644 --- a/app/views/admin/conference/_edit_form.html.haml +++ b/app/views/admin/conference/_edit_form.html.haml @@ -27,6 +27,4 @@ = f.input :sponsor_description, hint: markdown_hint("This will appear in the sponsor segment of the splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } = f.input :sponsor_email, hint: 'This will appear in the sponsor segment of the splash for the sponsors to contact to the organizers' = f.input :lodging_description, hint: markdown_hint("This will appear in the lodging segment of the splash."), input_html: { rows: 5, data: { provide: "markdown-editable" } } - - = dynamic_association :photos, "Photos", f = f.action :submit, :as => :button, :button_html => {:class => "btn btn-primary"} diff --git a/app/views/admin/conference/_photo_fields.html.erb b/app/views/admin/conference/_photo_fields.html.erb deleted file mode 100644 index 29a1f16b..00000000 --- a/app/views/admin/conference/_photo_fields.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -
- <%= f.inputs do %> - <%= image_tag(f.object.picture(:thumb)) unless f.object.picture.blank? %> - <%= f.input :picture, hint: 'This photo will appear in the gallery of the splash - so please give photos of banner sizes' %> - <%= f.input :description, :input_html => {:rows => 2 }, hint: 'This description will appear - at the bottom of each photo' %> - <%= remove_association_link :photo, f %> - <% end %> -
diff --git a/app/views/admin/photos/_form.html.haml b/app/views/admin/photos/_form.html.haml new file mode 100644 index 00000000..2c01af4c --- /dev/null +++ b/app/views/admin/photos/_form.html.haml @@ -0,0 +1,7 @@ += f.inputs do + - if !f.object.errors + = image_tag(f.object.picture(:thumb)) unless f.object.picture.blank? + = f.input :picture, hint: 'This photo will appear in the gallery of the splash so please give photos of banner sizes.' + = f.input :description, :input_html => {:rows => 2 }, hint: 'This description will appear at the bottom of each photo.' + .actions + = f.button 'Save Photo', :class => 'btn btn-primary' diff --git a/app/views/admin/photos/edit.html.haml b/app/views/admin/photos/edit.html.haml new file mode 100644 index 00000000..9b87054b --- /dev/null +++ b/app/views/admin/photos/edit.html.haml @@ -0,0 +1,6 @@ +%h1 Editing Photo + += semantic_form_for @photo, url: admin_conference_photo_path(conference_id: @conference.short_title, id: @photo.id) do |f| + = render 'form', f: f + += link_to 'Back', admin_conference_photos_path diff --git a/app/views/admin/photos/index.html.haml b/app/views/admin/photos/index.html.haml new file mode 100644 index 00000000..77f4f5d7 --- /dev/null +++ b/app/views/admin/photos/index.html.haml @@ -0,0 +1,22 @@ +%h1 Photos +%p.text-muted + Photo's will appear in the gallery of the conference splash page. +- @photos.each_slice(3) do |slice| + .row.row-flex.row-flex-wrap + - slice.each do |photo| + .col-md-4 + .thumbnail.flex-col + %h3.text-center + = photo.picture_file_name + = image_tag(photo.picture(:large), class: 'img-responsive', title: photo.description) + .caption.flex-grow + .caption + = link_to edit_admin_conference_photo_path(@conference.short_title, photo.id), class: 'btn btn-primary' do + %i.fa.fa-pencil-square-o + Edit + = link_to admin_conference_photo_path(@conference.short_title, photo.id), method: :delete, class: 'btn btn-danger' do + %i.fa.fa-times-circle + Delete +.row{'style'=>'padding-top: 10px;'} + .col-md-12 + = link_to 'New Photo', new_admin_conference_photo_path, class: 'btn btn-primary' diff --git a/app/views/admin/photos/new.html.haml b/app/views/admin/photos/new.html.haml new file mode 100644 index 00000000..68115b49 --- /dev/null +++ b/app/views/admin/photos/new.html.haml @@ -0,0 +1,6 @@ +%h1 New Photo + += semantic_form_for @photo, url: admin_conference_photos_path(conference_id: @conference.short_title) do |f| + = render 'form', f: f + += link_to 'Back', admin_conference_photos_path diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index b9f5e5db..31f8397b 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -35,8 +35,12 @@ Contact %li{:class=> "#{active_nav_li(admin_conference_commercials_path(@conference.short_title))}"} = link_to(admin_conference_commercials_path(@conference.short_title)) do - %span.fa.fa-comment + %span.fa.fa-film Commercials + %li{:class=> "#{active_nav_li(admin_conference_photos_path(@conference.short_title))}"} + = link_to(admin_conference_photos_path(@conference.short_title)) do + %span.fa.fa-picture-o + Photos %li{:class=> active_nav_li(admin_conference_events_path(@conference.short_title))} = link_to(admin_conference_events_path(@conference.short_title)) do %span.glyphicon.glyphicon-comment diff --git a/config/routes.rb b/config/routes.rb index c8bc7a05..030a4bb0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ Osem::Application.routes.draw do resources :people resources :conference do resource :contact, except: [:index, :new, :create, :show, :destroy] + resources :photos, except: [:show] resource :schedule, only: [:show, :update] resources :commercials, except: [:show] get '/stats' => 'stats#index' diff --git a/spec/factories/photos.rb b/spec/factories/photos.rb index 49180a0b..c3e69721 100644 --- a/spec/factories/photos.rb +++ b/spec/factories/photos.rb @@ -1,7 +1,9 @@ # Read about factories at https://github.com/thoughtbot/factory_girl +include ActionDispatch::TestProcess FactoryGirl.define do factory :photo do + picture { fixture_file_upload(Rails.root.join('app', 'assets', 'images', 'rails.png'), 'image/png') } picture_file_name 'rails.png' picture_content_type 'image/png' picture_file_size '1024' diff --git a/spec/features/photo_spec.rb b/spec/features/photo_spec.rb new file mode 100644 index 00000000..c9150b30 --- /dev/null +++ b/spec/features/photo_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +feature Photo do + + # It is necessary to use bang version of let to build roles before user + let!(:organizer_role) { create(:organizer_role) } + let!(:participant_role) { create(:participant_role) } + let!(:admin_role) { create(:admin_role) } + + shared_examples 'add and update photo' do |user| + scenario 'adds a new photo', feature: true, js: true do + expected_count = Photo.count + 1 + conference = create(:conference) + sign_in create(user) + + visit new_admin_conference_photo_path(conference.short_title) + + file_path = Rails.root.join('app', 'assets', 'images', 'rails.png') + attach_file('photo_picture', file_path) + fill_in 'photo_description', with: 'Lorem ipsum dolorem...' + + click_button 'Save Photo' + + expect(flash). + to eq('Photo was successfully created.') + expect(Photo.count).to eq(expected_count) + end + + scenario 'updates a photo', feature: true, js: true do + expected_count = Photo.count + 1 + conference = create(:conference) + photo = create(:photo) + sign_in create(user) + + visit edit_admin_conference_photo_path(conference.short_title, photo.id) + + file_path = Rails.root.join('app', 'assets', 'images', 'person_large.png') + attach_file('photo_picture', file_path) + fill_in 'photo_description', with: 'Lorem ipsum dolorem...' + + click_button 'Save Photo' + + expect(flash). + to eq('Photo was successfully updated.') + expect(Photo.count).to eq(expected_count) + end + + scenario 'adds a text file', feature: true, js: true do + expected_count = Photo.count + conference = create(:conference) + sign_in create(user) + + visit new_admin_conference_photo_path(conference.short_title) + + file_path = Rails.root + 'spec/fixtures/test.txt' + attach_file('photo_picture', file_path) + fill_in 'photo_description', with: 'Lorem ipsum dolorem...' + + click_button 'Save Photo' + + expect(flash). + to eq("A error prohibited this Photo from being saved: Picture content type is invalid. Picture is invalid.") + expect(Photo.count).to eq(expected_count) + end + end + + describe 'admin' do + it_behaves_like 'add and update photo', :admin + end + + describe 'organizer' do + it_behaves_like 'add and update photo', :organizer + end + +end diff --git a/spec/fixtures/test.txt b/spec/fixtures/test.txt new file mode 100644 index 00000000..7dc5f421 --- /dev/null +++ b/spec/fixtures/test.txt @@ -0,0 +1 @@ +Lorem ipsum dolorem... \ No newline at end of file