From dfbe17d046dc30caa076c0785746014d4d4d8922 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Sat, 8 Mar 2014 21:34:50 +0100 Subject: [PATCH 01/23] Poll input fields and data model now available question field of poll now in db fixed merge issues --- .../javascripts/app/views/publisher_view.js | 29 +++++++- app/assets/stylesheets/publisher.css.scss | 4 ++ .../stylesheets/publisher_blueprint.css.scss | 17 +++++ app/controllers/status_messages_controller.rb | 5 ++ app/models/poll.rb | 7 ++ app/models/status_message.rb | 1 + .../publisher/_publisher_blueprint.html.haml | 13 ++++ config/locales/diaspora/en.yml | 3 + db/migrate/20140308154022_create_polls.rb | 33 ++++++++++ db/schema.rb | 66 +++++++++++++------ spec/models/poll_spec.rb | 5 ++ 11 files changed, 161 insertions(+), 22 deletions(-) create mode 100644 app/models/poll.rb create mode 100644 db/migrate/20140308154022_create_polls.rb create mode 100644 spec/models/poll_spec.rb diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 675f4d4fd..791992ef2 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -23,6 +23,9 @@ app.views.Publisher = Backbone.View.extend({ "click .post_preview_button" : "createPostPreview", "textchange #status_message_fake_text": "handleTextchange", "click #locator" : "showLocation", + "click #poll_creator" : "showPollCreator", + "click #add_poll_answer" : "addPollAnswer", + "click .remove_poll_answer" : "removePollAnswer", "click #hide_location" : "destroyLocation", "keypress #location_address" : "avoidEnter" }, @@ -37,6 +40,8 @@ app.views.Publisher = Backbone.View.extend({ this.el_submit = this.$('input[type=submit], button#submit'); this.el_preview = this.$('button.post_preview_button'); this.el_photozone = this.$('#photodropzone'); + this.el_poll_creator = this.$('#poll_creator_wrapper'); + this.el_poll_answer = this.$('#poll_creator_wrapper .poll_answer'); // init mentions plugin Mentions.initialize(this.el_input); @@ -127,7 +132,6 @@ app.views.Publisher = Backbone.View.extend({ // lulz this code should be killed. var statusMessage = new app.models.Post(); - statusMessage.save({ "status_message" : { "text" : serializedForm["status_message[text]"] @@ -136,10 +140,12 @@ app.views.Publisher = Backbone.View.extend({ "photos" : serializedForm["photos[]"], "services" : serializedForm["services[]"], "location_address" : $("#location_address").val(), - "location_coords" : serializedForm["location[coords]"] + "location_coords" : serializedForm["location[coords]"], + "poll_question" : serializedForm["poll_question"] }, { url : "/status_messages", success : function() { + console.log(statusMessage); if(app.publisher) { $(app.publisher.el).trigger('ajax:success'); } @@ -171,6 +177,23 @@ app.views.Publisher = Backbone.View.extend({ } }, + showPollCreator: function(){ + this.el_poll_creator.toggle(); + }, + + addPollAnswer: function(){ + var clone = this.el_poll_answer.clone(); + var count_of_answers = this.el_poll_answer.size()+1; + clone.attr("name", "poll_answer_"+count_of_answers) + this.el_poll_answer.last().after(clone); + }, + + removePollAnswer: function(evt){ + if($(".poll_answer_input").size() > 1) { + $(evt.target).parent().remove(); + } + return false; + }, // avoid submitting form when pressing Enter key avoidEnter: function(evt){ if(evt.keyCode == 13) @@ -323,7 +346,7 @@ app.views.Publisher = Backbone.View.extend({ $(this.el).addClass("closed"); this.el_wrapper.removeClass("active"); this.el_input.css('height', ''); - + this.el_poll_creator.hide(); return this; }, diff --git a/app/assets/stylesheets/publisher.css.scss b/app/assets/stylesheets/publisher.css.scss index 0fe934716..08ff3cec0 100644 --- a/app/assets/stylesheets/publisher.css.scss +++ b/app/assets/stylesheets/publisher.css.scss @@ -59,6 +59,7 @@ resize: none; height: 50px; } + } &.active textarea { min-height: 70px; @@ -78,6 +79,7 @@ line-height: 20px !important; width: 100% !important; } + } &.with_attachments .row-fluid#photodropzone_container { border-top: 1px dashed $border-grey; @@ -162,6 +164,7 @@ margin-right: 5px; #file-upload, #locator, + #poll_creator, #hide_location { text-decoration: none !important; font-size: 16px; @@ -215,3 +218,4 @@ } } } + diff --git a/app/assets/stylesheets/publisher_blueprint.css.scss b/app/assets/stylesheets/publisher_blueprint.css.scss index 23e3a94ca..68a6f617f 100644 --- a/app/assets/stylesheets/publisher_blueprint.css.scss +++ b/app/assets/stylesheets/publisher_blueprint.css.scss @@ -309,8 +309,25 @@ } } } + #poll_creator { + @extend #locator; + right: 50px; + } + .btn { height: 19px; width: 19px; } } + +#poll_creator_wrapper { + display:none; +} + +.remove_poll_answer { + display:inline-block; +} + +.poll_answer_input { + display:inline-block !important; +} \ No newline at end of file diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index 83f92f3ac..78507fc81 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -49,6 +49,11 @@ class StatusMessagesController < ApplicationController @status_message = current_user.build_post(:status_message, params[:status_message]) @status_message.build_location(:address => params[:location_address], :coordinates => params[:location_coords]) if params[:location_address].present? + @status_message.build_poll(:question => params[:poll_question]) if params[:poll_question].present? + + #save all answers for poll + + @status_message.attach_photos_by_ids(params[:photos]) if @status_message.save diff --git a/app/models/poll.rb b/app/models/poll.rb new file mode 100644 index 000000000..15d770cc4 --- /dev/null +++ b/app/models/poll.rb @@ -0,0 +1,7 @@ +class Poll < ActiveRecord::Base + attr_accessible :question + + belongs_to :status_message + belongs_to :author, :class_name => :person, :foreign_key => :author_id + #has_many :poll_answers +end diff --git a/app/models/status_message.rb b/app/models/status_message.rb index 4e0dfd127..352e646b2 100644 --- a/app/models/status_message.rb +++ b/app/models/status_message.rb @@ -24,6 +24,7 @@ class StatusMessage < Post has_many :photos, :dependent => :destroy, :foreign_key => :status_message_guid, :primary_key => :guid has_one :location + has_one :poll # a StatusMessage is federated before its photos are so presence_of_content() fails erroneously if no text is present # therefore, we put the validation in a before_destory callback instead of a validation diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index b99d55958..0d4357cc0 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -28,12 +28,25 @@ %span#publisher-images %span.markdownIndications != t('shared.publisher.formatWithMarkdown', markdown_link: link_to(t('help.markdown'), 'https://diasporafoundation.org/formatting', target: :blank)) + #poll_creator.btn{:title => t('.create_poll')} + = image_tag 'icons/marker.png', :alt => t('.create_poll').titleize, :class => 'publisher_image' #locator.btn{:title => t('shared.publisher.get_location')} = image_tag 'icons/marker.png', :alt => t('shared.publisher.get_location').titleize, :class => 'publisher_image' #file-upload.btn{:title => t('shared.publisher.upload_photos')} = image_tag 'icons/camera.png', :alt => t('shared.publisher.upload_photos').titleize, :class => 'publisher_image' = hidden_field :location, :coords #location_container + #poll_creator_wrapper + = 'Poll creation' + %br + %br + %input{:id => 'poll_question', :placeholder => 'Question', :name => 'poll_question'} + %div{:class => 'poll_answer'} + %input{:class => 'poll_answer_input', :placeholder => 'Answer', :name => 'poll_answer_1'} + %a{:class => 'remove_poll_answer'} + = t('shared.publisher.poll.remove_poll_answer') + %div{:id => 'add_poll_answer', :class => 'button creation'} + = t('shared.publisher.poll.add_poll_answer') - if publisher_public = hidden_field_tag 'aspect_ids[]', "public" diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 08424ab0c..5e9fa2e9d 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -1037,6 +1037,9 @@ en: hello: "Hey everyone, I'm #%{new_user_tag}. " i_like: "I'm interested in %{tags}. " invited_by: "Thanks for the invite, " + poll: + remove_poll_answer: "Remove answer" + add_poll_answer: "Add answer" add_contact: enter_a_diaspora_username: "Enter a diaspora* username:" your_diaspora_username_is: "Your diaspora* username is: %{diaspora_handle}" diff --git a/db/migrate/20140308154022_create_polls.rb b/db/migrate/20140308154022_create_polls.rb new file mode 100644 index 000000000..4fd447974 --- /dev/null +++ b/db/migrate/20140308154022_create_polls.rb @@ -0,0 +1,33 @@ +class CreatePolls < ActiveRecord::Migration + def up + create_table :polls do |t| + t.string :question, :null => false + t.belongs_to :status_message, :null => false + t.boolean :status + t.timestamps + end + add_index :polls, :status_message_id + + create_table :poll_answers do |t| + t.string :answer, :null => false + t.belongs_to :poll, :null => false + end + add_index :poll_answers, :poll_id + + create_table :poll_participations do |t| + t.belongs_to :poll_answer, :null => false + t.belongs_to :author, :null => false + t.belongs_to :poll, :null => false + t.datetime :time + + t.timestamps + end + add_index :poll_participations, :poll_id + end + + def down + drop_table :polls + drop_table :poll_answers + drop_table :poll_participations + end +end diff --git a/db/schema.rb b/db/schema.rb index 60fab83be..fe5a33e04 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20140222162826) do +ActiveRecord::Schema.define(:version => 20140308154022) do create_table "account_deletions", :force => true do |t| t.string "diaspora_handle" @@ -283,6 +283,34 @@ ActiveRecord::Schema.define(:version => 20140222162826) do t.datetime "updated_at", :null => false end + create_table "poll_answers", :force => true do |t| + t.string "answer", :null => false + t.integer "poll_id", :null => false + end + + add_index "poll_answers", ["poll_id"], :name => "index_poll_answers_on_poll_id" + + create_table "poll_participations", :force => true do |t| + t.integer "poll_answer_id", :null => false + t.integer "author_id", :null => false + t.integer "poll_id", :null => false + t.datetime "time" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "poll_participations", ["poll_id"], :name => "index_poll_participations_on_poll_id" + + create_table "polls", :force => true do |t| + t.string "question", :null => false + t.integer "status_message_id", :null => false + t.boolean "status" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "polls", ["status_message_id"], :name => "index_polls_on_status_message_id" + create_table "post_reports", :force => true do |t| t.integer "post_id", :null => false t.string "user_id" @@ -502,36 +530,36 @@ ActiveRecord::Schema.define(:version => 20140222162826) do add_index "users", ["invitation_token"], :name => "index_users_on_invitation_token" add_index "users", ["username"], :name => "index_users_on_username", :unique => true - add_foreign_key "aspect_memberships", "aspects", :name => "aspect_memberships_aspect_id_fk", :dependent => :delete - add_foreign_key "aspect_memberships", "contacts", :name => "aspect_memberships_contact_id_fk", :dependent => :delete + add_foreign_key "aspect_memberships", "aspects", name: "aspect_memberships_aspect_id_fk", dependent: :delete + add_foreign_key "aspect_memberships", "contacts", name: "aspect_memberships_contact_id_fk", dependent: :delete - add_foreign_key "aspect_visibilities", "aspects", :name => "aspect_visibilities_aspect_id_fk", :dependent => :delete + add_foreign_key "aspect_visibilities", "aspects", name: "aspect_visibilities_aspect_id_fk", dependent: :delete - add_foreign_key "comments", "people", :name => "comments_author_id_fk", :column => "author_id", :dependent => :delete + add_foreign_key "comments", "people", name: "comments_author_id_fk", column: "author_id", dependent: :delete - add_foreign_key "contacts", "people", :name => "contacts_person_id_fk", :dependent => :delete + add_foreign_key "contacts", "people", name: "contacts_person_id_fk", dependent: :delete - add_foreign_key "conversation_visibilities", "conversations", :name => "conversation_visibilities_conversation_id_fk", :dependent => :delete - add_foreign_key "conversation_visibilities", "people", :name => "conversation_visibilities_person_id_fk", :dependent => :delete + add_foreign_key "conversation_visibilities", "conversations", name: "conversation_visibilities_conversation_id_fk", dependent: :delete + add_foreign_key "conversation_visibilities", "people", name: "conversation_visibilities_person_id_fk", dependent: :delete - add_foreign_key "conversations", "people", :name => "conversations_author_id_fk", :column => "author_id", :dependent => :delete + add_foreign_key "conversations", "people", name: "conversations_author_id_fk", column: "author_id", dependent: :delete - add_foreign_key "invitations", "users", :name => "invitations_recipient_id_fk", :column => "recipient_id", :dependent => :delete - add_foreign_key "invitations", "users", :name => "invitations_sender_id_fk", :column => "sender_id", :dependent => :delete + add_foreign_key "invitations", "users", name: "invitations_recipient_id_fk", column: "recipient_id", dependent: :delete + add_foreign_key "invitations", "users", name: "invitations_sender_id_fk", column: "sender_id", dependent: :delete - add_foreign_key "likes", "people", :name => "likes_author_id_fk", :column => "author_id", :dependent => :delete + add_foreign_key "likes", "people", name: "likes_author_id_fk", column: "author_id", dependent: :delete - add_foreign_key "messages", "conversations", :name => "messages_conversation_id_fk", :dependent => :delete - add_foreign_key "messages", "people", :name => "messages_author_id_fk", :column => "author_id", :dependent => :delete + add_foreign_key "messages", "conversations", name: "messages_conversation_id_fk", dependent: :delete + add_foreign_key "messages", "people", name: "messages_author_id_fk", column: "author_id", dependent: :delete - add_foreign_key "notification_actors", "notifications", :name => "notification_actors_notification_id_fk", :dependent => :delete + add_foreign_key "notification_actors", "notifications", name: "notification_actors_notification_id_fk", dependent: :delete - add_foreign_key "posts", "people", :name => "posts_author_id_fk", :column => "author_id", :dependent => :delete + add_foreign_key "posts", "people", name: "posts_author_id_fk", column: "author_id", dependent: :delete - add_foreign_key "profiles", "people", :name => "profiles_person_id_fk", :dependent => :delete + add_foreign_key "profiles", "people", name: "profiles_person_id_fk", dependent: :delete - add_foreign_key "services", "users", :name => "services_user_id_fk", :dependent => :delete + add_foreign_key "services", "users", name: "services_user_id_fk", dependent: :delete - add_foreign_key "share_visibilities", "contacts", :name => "post_visibilities_contact_id_fk", :dependent => :delete + add_foreign_key "share_visibilities", "contacts", name: "post_visibilities_contact_id_fk", dependent: :delete end diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb new file mode 100644 index 000000000..8f2cabf75 --- /dev/null +++ b/spec/models/poll_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Poll do + pending "add some examples to (or delete) #{__FILE__}" +end From fe67bdf2e79d44928b99cca672067f3deb3934b5 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Thu, 20 Mar 2014 22:04:02 +0100 Subject: [PATCH 02/23] added tests for poll federation and impl for the federation itself. Still in progess --- .../javascripts/app/views/publisher_view.js | 4 +- .../stylesheets/publisher_blueprint.css.scss | 8 +- app/models/poll.rb | 16 +++- app/models/poll_answer.rb | 10 +++ app/models/poll_participation.rb | 55 +++++++++++++ app/models/status_message.rb | 1 + app/models/user/social_actions.rb | 5 ++ .../publisher/_publisher_blueprint.html.haml | 10 +-- db/migrate/20140308154022_create_polls.rb | 6 +- db/schema.rb | 16 ++-- lib/diaspora/parser.rb | 1 + spec/models/poll_answer_spec.rb | 10 +++ spec/models/poll_participation_spec.rb | 78 +++++++++++++++++++ spec/models/poll_spec.rb | 21 ++++- spec/models/status_message_spec.rb | 25 ++++++ spec/models/user/social_actions_spec.rb | 10 +++ 16 files changed, 251 insertions(+), 25 deletions(-) create mode 100644 app/models/poll_answer.rb create mode 100644 app/models/poll_participation.rb create mode 100644 spec/models/poll_answer_spec.rb create mode 100644 spec/models/poll_participation_spec.rb diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 791992ef2..10f01896b 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -183,8 +183,8 @@ app.views.Publisher = Backbone.View.extend({ addPollAnswer: function(){ var clone = this.el_poll_answer.clone(); - var count_of_answers = this.el_poll_answer.size()+1; - clone.attr("name", "poll_answer_"+count_of_answers) + var count_of_answers = $('.poll_answer_input').size()+1; + clone.children('.poll_answer_input').attr("name", "poll_answer_"+count_of_answers); this.el_poll_answer.last().after(clone); }, diff --git a/app/assets/stylesheets/publisher_blueprint.css.scss b/app/assets/stylesheets/publisher_blueprint.css.scss index 68a6f617f..879917660 100644 --- a/app/assets/stylesheets/publisher_blueprint.css.scss +++ b/app/assets/stylesheets/publisher_blueprint.css.scss @@ -322,12 +322,10 @@ #poll_creator_wrapper { display:none; + border: 1px solid $border-dark-grey; + padding:5px; } .remove_poll_answer { - display:inline-block; + display:inline; } - -.poll_answer_input { - display:inline-block !important; -} \ No newline at end of file diff --git a/app/models/poll.rb b/app/models/poll.rb index 15d770cc4..896908b50 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -1,7 +1,15 @@ class Poll < ActiveRecord::Base - attr_accessible :question - + include Diaspora::Federated::Base + include Diaspora::Guid + attr_accessible :question, :poll_answers belongs_to :status_message - belongs_to :author, :class_name => :person, :foreign_key => :author_id - #has_many :poll_answers + has_many :poll_answers + has_many :poll_participations + + delegate :author, :author_id, :subscribers, to: :status_message + + #forward subscribers request to status message, because a poll is just attached to a status message and is not sharable itself + #def subscribers(user) + # status_message.subscribers(user) + #end end diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb new file mode 100644 index 000000000..7893a8b25 --- /dev/null +++ b/app/models/poll_answer.rb @@ -0,0 +1,10 @@ +class PollAnswer < ActiveRecord::Base + + include Diaspora::Federated::Base + include Diaspora::Guid + + belongs_to :poll + has_many :poll_participations + + xml_attr :answer +end diff --git a/app/models/poll_participation.rb b/app/models/poll_participation.rb new file mode 100644 index 000000000..a5990f12e --- /dev/null +++ b/app/models/poll_participation.rb @@ -0,0 +1,55 @@ +class PollParticipation < ActiveRecord::Base + + include Diaspora::Federated::Base + + include Diaspora::Guid + include Diaspora::Relayable + belongs_to :poll + belongs_to :poll_answer + belongs_to :author, :class_name => 'Person', :foreign_key => :author_id + xml_attr :diaspora_handle + xml_attr :poll_answer_guid + + def parent_class + Poll + end + + def parent + self.poll + end + + def poll_answer_guid + poll_answer.guid + end + + def poll_answer_guid= new_poll_answer_guid + self.poll_answer = PollAnswer.where(:guid => new_poll_answer_guid).first + end + + def parent= parent + self.poll = parent + end + + def diaspora_handle + self.author.diaspora_handle + end + + def diaspora_handle= nh + self.author = Webfinger.new(nh).fetch + end + + class Generator < Federated::Generator + def self.federated_class + PollParticipation + end + + def initialize(person, target, poll_answer) + @poll_answer = poll_answer + super(person, target) + end + + def relayable_options + {:poll => @target.poll, :poll_answer => @poll_answer} + end + end +end diff --git a/app/models/status_message.rb b/app/models/status_message.rb index 352e646b2..aa79c69f7 100644 --- a/app/models/status_message.rb +++ b/app/models/status_message.rb @@ -20,6 +20,7 @@ class StatusMessage < Post xml_attr :raw_message xml_attr :photos, :as => [Photo] xml_attr :location, :as => Location + xml_attr :poll, :as => Poll has_many :photos, :dependent => :destroy, :foreign_key => :status_message_guid, :primary_key => :guid diff --git a/app/models/user/social_actions.rb b/app/models/user/social_actions.rb index 6bb547f40..ccc30b484 100644 --- a/app/models/user/social_actions.rb +++ b/app/models/user/social_actions.rb @@ -13,6 +13,11 @@ module User::SocialActions Like::Generator.new(self, target).create!(opts) end + def participate_in_poll!(target, answer, opts={}) + find_or_create_participation!(target) + PollParticipation::Generator.new(self, target, answer).create!(opts) + end + def reshare!(target, opts={}) find_or_create_participation!(target) reshare = build_post(:reshare, :root_guid => target.guid) diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index 0d4357cc0..b5eb1936f 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -36,14 +36,14 @@ = image_tag 'icons/camera.png', :alt => t('shared.publisher.upload_photos').titleize, :class => 'publisher_image' = hidden_field :location, :coords #location_container + %br #poll_creator_wrapper = 'Poll creation' %br - %br - %input{:id => 'poll_question', :placeholder => 'Question', :name => 'poll_question'} - %div{:class => 'poll_answer'} - %input{:class => 'poll_answer_input', :placeholder => 'Answer', :name => 'poll_answer_1'} - %a{:class => 'remove_poll_answer'} + %input{:id => 'poll_question', :placeholder => 'Question', :name => 'poll_question', :class => 'span-12'} + %div{:class => 'poll_answer span-12'} + %input{:class => 'poll_answer_input span-8', :placeholder => 'Answer', :name => 'poll_answer_1'} + %a{:class => 'remove_poll_answer span-3'} = t('shared.publisher.poll.remove_poll_answer') %div{:id => 'add_poll_answer', :class => 'button creation'} = t('shared.publisher.poll.add_poll_answer') diff --git a/db/migrate/20140308154022_create_polls.rb b/db/migrate/20140308154022_create_polls.rb index 4fd447974..52188cdc6 100644 --- a/db/migrate/20140308154022_create_polls.rb +++ b/db/migrate/20140308154022_create_polls.rb @@ -4,6 +4,7 @@ class CreatePolls < ActiveRecord::Migration t.string :question, :null => false t.belongs_to :status_message, :null => false t.boolean :status + t.string :guid t.timestamps end add_index :polls, :status_message_id @@ -11,6 +12,7 @@ class CreatePolls < ActiveRecord::Migration create_table :poll_answers do |t| t.string :answer, :null => false t.belongs_to :poll, :null => false + t.string :guid end add_index :poll_answers, :poll_id @@ -18,7 +20,9 @@ class CreatePolls < ActiveRecord::Migration t.belongs_to :poll_answer, :null => false t.belongs_to :author, :null => false t.belongs_to :poll, :null => false - t.datetime :time + t.string :guid + t.text :author_signature + t.text :parent_author_signature t.timestamps end diff --git a/db/schema.rb b/db/schema.rb index fe5a33e04..91253852f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -286,17 +286,20 @@ ActiveRecord::Schema.define(:version => 20140308154022) do create_table "poll_answers", :force => true do |t| t.string "answer", :null => false t.integer "poll_id", :null => false + t.string "guid" end add_index "poll_answers", ["poll_id"], :name => "index_poll_answers_on_poll_id" create_table "poll_participations", :force => true do |t| - t.integer "poll_answer_id", :null => false - t.integer "author_id", :null => false - t.integer "poll_id", :null => false - t.datetime "time" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.integer "poll_answer_id", :null => false + t.integer "author_id", :null => false + t.integer "poll_id", :null => false + t.string "guid" + t.text "author_signature" + t.text "parent_author_signature" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false end add_index "poll_participations", ["poll_id"], :name => "index_poll_participations_on_poll_id" @@ -305,6 +308,7 @@ ActiveRecord::Schema.define(:version => 20140308154022) do t.string "question", :null => false t.integer "status_message_id", :null => false t.boolean "status" + t.string "guid" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end diff --git a/lib/diaspora/parser.rb b/lib/diaspora/parser.rb index 1d2c50092..5665d74af 100644 --- a/lib/diaspora/parser.rb +++ b/lib/diaspora/parser.rb @@ -5,6 +5,7 @@ module Diaspora module Parser def self.from_xml(xml) + puts xml doc = Nokogiri::XML(xml) { |cfg| cfg.noblanks } return unless body = doc.xpath("/XML/post").children.first class_name = body.name.gsub('-', '/') diff --git a/spec/models/poll_answer_spec.rb b/spec/models/poll_answer_spec.rb new file mode 100644 index 000000000..b49465034 --- /dev/null +++ b/spec/models/poll_answer_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' + +describe PollAnswer do +before :do + describe 'validation' do + it 'should ...' do + + end + end +end \ No newline at end of file diff --git a/spec/models/poll_participation_spec.rb b/spec/models/poll_participation_spec.rb new file mode 100644 index 000000000..ee25b378a --- /dev/null +++ b/spec/models/poll_participation_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' +require Rails.root.join("spec", "shared_behaviors", "relayable") + +describe PollParticipation do + + before do + @alices_aspect = alice.aspects.first + @status = bob.post(:status_message, :text => "hello", :to => bob.aspects.first.id) + end + + describe 'xml' do + before do + @poll_participant = FactoryGirl.create(:user) + @poll_participant_aspect = @poll_participant.aspects.create(:name => "bruisers") + connect_users(alice, @alices_aspect, @poll_participant, @poll_participant_aspect) + @poll = Poll.new(:question => "hi") + @poll.poll_answers.build(:answer => "a") + @poll.poll_answers.build(:answer => "b") + @post = alice.post :status_message, :text => "hello", :to => @alices_aspect.id + @post.poll = @poll + @poll_participation = @poll_participant.participate_in_poll!(@post, @poll.poll_answers.first) + @xml = @poll_participation.to_xml.to_s + end + + it 'serializes the sender handle' do + @xml.include?(@poll_participation.diaspora_handle).should be_true + end + + it 'serializes the poll_guid' do + @xml.should include(@poll.guid) + end + + it 'serializes the poll_answer_guid' do + @xml.should include(@poll_participation.poll_answer.guid) + end + + describe 'marshalling' do + before do + @marshalled_poll_participation = PollParticipation.from_xml(@xml) + end + + it 'marshals the author' do + @marshalled_poll_participation.author.should == @poll_participant.person + end + + it 'marshals the answer' do + @marshalled_poll_participation.poll_answer.should == @poll_participation.poll_answer + end + + it 'marshals the poll' do + @marshalled_poll_participation.poll.should == @poll + end + end + end + + # describe 'it is relayable' do + # before do + # @poll = Poll.new + # @poll_answer = PollAnswer.new(:answer => '1') + # @poll_answer2 = PollAnswer.new(:answer => '1') + # @poll.answers << [poll_answer, poll_answer2] + # @status.poll = @poll + + # @local_luke, @local_leia, @remote_raphael = set_up_friends + # @remote_parent = FactoryGirl.build(:status_message, :author => @remote_raphael) + # @local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first + + # @object_by_parent_author = @local_luke.vote!(@local_parent, @poll_answer) + # @object_by_recipient = @local_leia.vote!(@local_parent, @poll_answer) + # @dup_object_by_parent_author = @object_by_parent_author.dup + + # @object_on_remote_parent = @local_luke.comment!(@remote_parent, "Yeah, it was great") + # end + + # let(:build_object) { alice.build_poll_participation(:poll => @poll, :poll_answer => @poll_answer) } + # it_should_behave_like 'it is relayable' + # end +end diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb index 8f2cabf75..ab5641fc7 100644 --- a/spec/models/poll_spec.rb +++ b/spec/models/poll_spec.rb @@ -1,5 +1,22 @@ require 'spec_helper' describe Poll do - pending "add some examples to (or delete) #{__FILE__}" -end + before do + @poll = Poll.new(:question => "What do you think about apples?") + end + + describe 'validation' do + it 'should create no poll when it has less than two answers' do + @poll.poll_answers << PollAnswer.new(:answer => '1') + @poll.should_not be_valid + end + + it 'should create a poll when it has more than two answers' do + @poll.poll_answers << PollAnswer.new(:answer => '1') + @poll.poll_answers << PollAnswer.new(:answer => '2') + @poll.should be_valid + end + end + + #TODO test if delegation of subscribers works +end \ No newline at end of file diff --git a/spec/models/status_message_spec.rb b/spec/models/status_message_spec.rb index 7ee8b4bc5..c68a82147 100644 --- a/spec/models/status_message_spec.rb +++ b/spec/models/status_message_spec.rb @@ -350,6 +350,31 @@ STR end end end + + context 'with a poll' do + before do + @message.poll = Poll.new(coordinates: "1, 2").tap(&:save) + @xml = @message.to_xml.to_s + end + + it 'serializes the location' do + @xml.should include "location" + @xml.should include "lat" + @xml.should include "lng" + end + + describe ".from_xml" do + before do + @marshalled = StatusMessage.from_xml(@xml) + end + + it 'marshals the location' do + @marshalled.location.should be_present + end + end + end + + end describe '#after_dispatch' do diff --git a/spec/models/user/social_actions_spec.rb b/spec/models/user/social_actions_spec.rb index 33c99e675..6ab83e4c5 100644 --- a/spec/models/user/social_actions_spec.rb +++ b/spec/models/user/social_actions_spec.rb @@ -83,4 +83,14 @@ describe User::SocialActions do @status.reload.likes.should == likes end end + + describe 'User#participate_in_poll!' do + before do + @bobs_aspect = bob.aspects.where(:name => "generic").first + poll = Poll.new(:poll_answers => [PollAnswer.new(:answer => "1"), PollAnswer.new(:answer => "2")]) + @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id, :poll => poll) + end + it "sets the poll answer id" do + alice.participate_in_poll!(@status, 1).poll_answer.answer.should == "1" + end end \ No newline at end of file From 5d560609e40505cda4cb90f34292bd4b291c7b4a Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Fri, 21 Mar 2014 12:20:01 +0100 Subject: [PATCH 03/23] poll_participation_spec no longer fails, added poll_participation factory --- app/models/poll.rb | 7 ++--- spec/factories.rb | 17 +++++++++++ spec/models/poll_participation_spec.rb | 41 ++++++++++++++------------ 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/app/models/poll.rb b/app/models/poll.rb index 896908b50..586e18154 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -6,10 +6,7 @@ class Poll < ActiveRecord::Base has_many :poll_answers has_many :poll_participations - delegate :author, :author_id, :subscribers, to: :status_message + #forward some requests to status message, because a poll is just attached to a status message and is not sharable itself + delegate :author, :author_id, :public?, :subscribers, to: :status_message - #forward subscribers request to status message, because a poll is just attached to a status message and is not sharable itself - #def subscribers(user) - # status_message.subscribers(user) - #end end diff --git a/spec/factories.rb b/spec/factories.rb index fcede7e1b..232e3a15b 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -92,6 +92,12 @@ FactoryGirl.define do end end + factory(:status_message_with_poll, :parent => :status_message) do + after(:build) do |sm| + FactoryGirl.create(:poll, :status_message => sm) + end + end + factory(:status_message_with_photo, :parent => :status_message) do sequence(:text) { |n| "There are #{n} ninjas in this photo." } after(:build) do |sm| @@ -107,6 +113,17 @@ FactoryGirl.define do end end + factory(:poll) do + sequence(:question) { |n| "What do you think about #{n} ninjas?" } + after(:build) do |p| + FactoryGirl.create(:poll_answer, :poll => p) + end + end + + factory(:poll_answer) do + sequence(:answer) { |n| "#{n} questionmarks" } + end + factory(:photo) do sequence(:random_string) {|n| SecureRandom.hex(10) } association :author, :factory => :person diff --git a/spec/models/poll_participation_spec.rb b/spec/models/poll_participation_spec.rb index ee25b378a..68c3fcfdf 100644 --- a/spec/models/poll_participation_spec.rb +++ b/spec/models/poll_participation_spec.rb @@ -6,6 +6,10 @@ describe PollParticipation do before do @alices_aspect = alice.aspects.first @status = bob.post(:status_message, :text => "hello", :to => bob.aspects.first.id) + @poll = Poll.new(:question => 'Who is in charge?') + @poll.poll_answers.build(:answer => "a") + @poll.poll_answers.build(:answer => "b") + @status.poll = @poll end describe 'xml' do @@ -53,26 +57,25 @@ describe PollParticipation do end end - # describe 'it is relayable' do - # before do - # @poll = Poll.new - # @poll_answer = PollAnswer.new(:answer => '1') - # @poll_answer2 = PollAnswer.new(:answer => '1') - # @poll.answers << [poll_answer, poll_answer2] - # @status.poll = @poll + describe 'it is relayable' do + before do + @local_luke, @local_leia, @remote_raphael = set_up_friends + @remote_parent = FactoryGirl.build(:status_message_with_poll, :author => @remote_raphael) + + @local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first + @poll2 = Poll.new(:question => 'Who is now in charge?') + @poll2.poll_answers.build(:answer => "a") + @poll2.poll_answers.build(:answer => "b") + @local_parent.poll = @poll2 - # @local_luke, @local_leia, @remote_raphael = set_up_friends - # @remote_parent = FactoryGirl.build(:status_message, :author => @remote_raphael) - # @local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first + @object_by_parent_author = @local_luke.participate_in_poll!(@local_parent, @poll.poll_answers.first) + @object_by_recipient = @local_leia.participate_in_poll!(@local_parent, @poll.poll_answers.first) + @dup_object_by_parent_author = @object_by_parent_author.dup - # @object_by_parent_author = @local_luke.vote!(@local_parent, @poll_answer) - # @object_by_recipient = @local_leia.vote!(@local_parent, @poll_answer) - # @dup_object_by_parent_author = @object_by_parent_author.dup + @object_on_remote_parent = @local_luke.participate_in_poll!(@remote_parent, @poll.poll_answers.first) + end - # @object_on_remote_parent = @local_luke.comment!(@remote_parent, "Yeah, it was great") - # end - - # let(:build_object) { alice.build_poll_participation(:poll => @poll, :poll_answer => @poll_answer) } - # it_should_behave_like 'it is relayable' - # end + let(:build_object) { PollParticipation::Generator.new(alice, @status, @poll.poll_answers.first).build } + it_should_behave_like 'it is relayable' + end end From 8a4f833d1def9ee780f958bee584c3a54c13c009 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Fri, 21 Mar 2014 18:51:40 +0100 Subject: [PATCH 04/23] added more tests for the poll federation + fixed broken rspec tests --- app/models/poll.rb | 9 ++++++++ app/models/poll_answer.rb | 6 ++++++ app/models/poll_participation.rb | 19 +++++++++++++++++ config/locales/diaspora/en.yml | 8 ++++++++ db/migrate/20140308154022_create_polls.rb | 1 + db/schema.rb | 5 +++-- lib/diaspora/parser.rb | 1 - spec/factories.rb | 3 ++- spec/models/poll_answer_spec.rb | 21 ++++++++++++++----- spec/models/poll_participation_spec.rb | 25 +++++++++++++++++++---- spec/models/poll_spec.rb | 10 ++++----- spec/models/status_message_spec.rb | 18 +++++++++------- spec/models/user/social_actions_spec.rb | 25 +++++++++++++++++++---- 13 files changed, 121 insertions(+), 30 deletions(-) diff --git a/app/models/poll.rb b/app/models/poll.rb index 586e18154..778f654ca 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -6,7 +6,16 @@ class Poll < ActiveRecord::Base has_many :poll_answers has_many :poll_participations + xml_attr :question + xml_attr :poll_answers, :as => [PollAnswer] + #forward some requests to status message, because a poll is just attached to a status message and is not sharable itself delegate :author, :author_id, :public?, :subscribers, to: :status_message + validate :enough_poll_answers + + def enough_poll_answers + errors.add(:poll_answers, I18n.t("activerecord.errors.models.poll.attributes.poll_answers.not_enough_poll_answers")) if poll_answers.size < 2 + end + end diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb index 7893a8b25..14ee658cf 100644 --- a/app/models/poll_answer.rb +++ b/app/models/poll_answer.rb @@ -7,4 +7,10 @@ class PollAnswer < ActiveRecord::Base has_many :poll_participations xml_attr :answer + + def update_vote_counter + self.vote_count = self.vote_count + 1 + self.save! + end + end diff --git a/app/models/poll_participation.rb b/app/models/poll_participation.rb index a5990f12e..c6c2ee85c 100644 --- a/app/models/poll_participation.rb +++ b/app/models/poll_participation.rb @@ -9,6 +9,13 @@ class PollParticipation < ActiveRecord::Base belongs_to :author, :class_name => 'Person', :foreign_key => :author_id xml_attr :diaspora_handle xml_attr :poll_answer_guid + validate :not_already_participated + + after_commit :update_vote_counter, :on => :create + + def update_vote_counter + self.poll_answer.update_vote_counter + end def parent_class Poll @@ -38,6 +45,18 @@ class PollParticipation < ActiveRecord::Base self.author = Webfinger.new(nh).fetch end + def not_already_participated + if self.poll == nil + return + end + + existing = PollParticipation.where(author_id: self.author.id, poll_id: self.poll.id) + if existing.first != self and existing.count != 0 + self.errors.add(:poll, I18n.t("errors.models.poll_participations.attributes.poll.already_participated")) + end + end + + class Generator < Federated::Generator def self.federated_class PollParticipation diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 5e9fa2e9d..2f36c7c38 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -77,6 +77,14 @@ en: attributes: root_guid: taken: "That good, huh? You've already reshared that post!" + poll: + attributes: + poll_answers: + not_enough_poll_answers: "Not enough poll options provided." + poll_participation: + attributes: + poll: + already_participated: "You've already participated in this poll!" error_messages: helper: invalid_fields: "Invalid Fields" diff --git a/db/migrate/20140308154022_create_polls.rb b/db/migrate/20140308154022_create_polls.rb index 52188cdc6..f2d84ba6a 100644 --- a/db/migrate/20140308154022_create_polls.rb +++ b/db/migrate/20140308154022_create_polls.rb @@ -13,6 +13,7 @@ class CreatePolls < ActiveRecord::Migration t.string :answer, :null => false t.belongs_to :poll, :null => false t.string :guid + t.integer :vote_count, :default => 0 end add_index :poll_answers, :poll_id diff --git a/db/schema.rb b/db/schema.rb index 91253852f..97f7cb6c2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -284,9 +284,10 @@ ActiveRecord::Schema.define(:version => 20140308154022) do end create_table "poll_answers", :force => true do |t| - t.string "answer", :null => false - t.integer "poll_id", :null => false + t.string "answer", :null => false + t.integer "poll_id", :null => false t.string "guid" + t.integer "vote_count", :default => 0 end add_index "poll_answers", ["poll_id"], :name => "index_poll_answers_on_poll_id" diff --git a/lib/diaspora/parser.rb b/lib/diaspora/parser.rb index 5665d74af..1d2c50092 100644 --- a/lib/diaspora/parser.rb +++ b/lib/diaspora/parser.rb @@ -5,7 +5,6 @@ module Diaspora module Parser def self.from_xml(xml) - puts xml doc = Nokogiri::XML(xml) { |cfg| cfg.noblanks } return unless body = doc.xpath("/XML/post").children.first class_name = body.name.gsub('-', '/') diff --git a/spec/factories.rb b/spec/factories.rb index 232e3a15b..ac040e185 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -116,7 +116,8 @@ FactoryGirl.define do factory(:poll) do sequence(:question) { |n| "What do you think about #{n} ninjas?" } after(:build) do |p| - FactoryGirl.create(:poll_answer, :poll => p) + p.poll_answers << FactoryGirl.build(:poll_answer) + p.poll_answers << FactoryGirl.build(:poll_answer) end end diff --git a/spec/models/poll_answer_spec.rb b/spec/models/poll_answer_spec.rb index b49465034..aa53d5261 100644 --- a/spec/models/poll_answer_spec.rb +++ b/spec/models/poll_answer_spec.rb @@ -1,10 +1,21 @@ require 'spec_helper' describe PollAnswer do -before :do - describe 'validation' do - it 'should ...' do - - end + before do + @status = FactoryGirl.create(:status_message_with_poll) + @user = alice + @answer = @status.poll.poll_answers.first end + + describe 'counter cache' do + it 'increments the counter cache on the answer' do + lambda { + alice.participate_in_poll!(@status, @answer) + }.should change{ + @answer.reload.vote_count + }.by(1) + end + + end + end \ No newline at end of file diff --git a/spec/models/poll_participation_spec.rb b/spec/models/poll_participation_spec.rb index 68c3fcfdf..26fbd10fc 100644 --- a/spec/models/poll_participation_spec.rb +++ b/spec/models/poll_participation_spec.rb @@ -12,6 +12,23 @@ describe PollParticipation do @status.poll = @poll end + describe 'validation' do + it 'does forbid multiple participations in the same poll' do + expect { + 2.times do |run| + bob.participate_in_poll!(@status, @poll.poll_answers.first) + end + }.to raise_error + end + + it 'does allow a one time participation in a poll' do + expect { + bob.participate_in_poll!(@status, @poll.poll_answers.first) + }.to_not raise_error + end + + end + describe 'xml' do before do @poll_participant = FactoryGirl.create(:user) @@ -61,18 +78,18 @@ describe PollParticipation do before do @local_luke, @local_leia, @remote_raphael = set_up_friends @remote_parent = FactoryGirl.build(:status_message_with_poll, :author => @remote_raphael) - + @local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first @poll2 = Poll.new(:question => 'Who is now in charge?') @poll2.poll_answers.build(:answer => "a") @poll2.poll_answers.build(:answer => "b") @local_parent.poll = @poll2 - @object_by_parent_author = @local_luke.participate_in_poll!(@local_parent, @poll.poll_answers.first) - @object_by_recipient = @local_leia.participate_in_poll!(@local_parent, @poll.poll_answers.first) + @object_by_parent_author = @local_luke.participate_in_poll!(@local_parent, @poll2.poll_answers.first) + @object_by_recipient = @local_leia.participate_in_poll!(@local_parent, @poll2.poll_answers.first) @dup_object_by_parent_author = @object_by_parent_author.dup - @object_on_remote_parent = @local_luke.participate_in_poll!(@remote_parent, @poll.poll_answers.first) + @object_on_remote_parent = @local_luke.participate_in_poll!(@remote_parent, @remote_parent.poll.poll_answers.first) end let(:build_object) { PollParticipation::Generator.new(alice, @status, @poll.poll_answers.first).build } diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb index ab5641fc7..c94c08e33 100644 --- a/spec/models/poll_spec.rb +++ b/spec/models/poll_spec.rb @@ -6,17 +6,15 @@ describe Poll do end describe 'validation' do - it 'should create no poll when it has less than two answers' do - @poll.poll_answers << PollAnswer.new(:answer => '1') + it 'should not create a poll when it has less than two answers' do + @poll.poll_answers.build(:answer => '1') @poll.should_not be_valid end it 'should create a poll when it has more than two answers' do - @poll.poll_answers << PollAnswer.new(:answer => '1') - @poll.poll_answers << PollAnswer.new(:answer => '2') + @poll.poll_answers.build(:answer => '1') + @poll.poll_answers.build(:answer => '2') @poll.should be_valid end end - - #TODO test if delegation of subscribers works end \ No newline at end of file diff --git a/spec/models/status_message_spec.rb b/spec/models/status_message_spec.rb index c68a82147..297a3f269 100644 --- a/spec/models/status_message_spec.rb +++ b/spec/models/status_message_spec.rb @@ -353,14 +353,14 @@ STR context 'with a poll' do before do - @message.poll = Poll.new(coordinates: "1, 2").tap(&:save) + @message.poll = FactoryGirl.create(:poll, :status_message => @message) @xml = @message.to_xml.to_s end - it 'serializes the location' do - @xml.should include "location" - @xml.should include "lat" - @xml.should include "lng" + it 'serializes the poll' do + @xml.should include "poll" + @xml.should include "question" + @xml.should include "poll_answer" end describe ".from_xml" do @@ -368,8 +368,12 @@ STR @marshalled = StatusMessage.from_xml(@xml) end - it 'marshals the location' do - @marshalled.location.should be_present + it 'marshals the poll' do + @marshalled.poll.should be_present + end + + it 'marshals the poll answers' do + @marshalled.poll.poll_answers.size.should == 2 end end end diff --git a/spec/models/user/social_actions_spec.rb b/spec/models/user/social_actions_spec.rb index 6ab83e4c5..de486010d 100644 --- a/spec/models/user/social_actions_spec.rb +++ b/spec/models/user/social_actions_spec.rb @@ -16,7 +16,7 @@ describe User::SocialActions do alice.participations.last.target.should == @status end - it "creates the like" do + it "creates the comment" do lambda{ alice.comment!(@status, "bro") }.should change(Comment, :count).by(1) end @@ -87,10 +87,27 @@ describe User::SocialActions do describe 'User#participate_in_poll!' do before do @bobs_aspect = bob.aspects.where(:name => "generic").first - poll = Poll.new(:poll_answers => [PollAnswer.new(:answer => "1"), PollAnswer.new(:answer => "2")]) - @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id, :poll => poll) + @status = bob.post(:status_message, :text => "hello", :to => @bobs_aspect.id) + @poll = FactoryGirl.create(:poll, :status_message => @status) + @answer = @poll.poll_answers.first end + + it "federates" do + Participation::Generator.any_instance.stub(:create!) + Postzord::Dispatcher.should_receive(:defer_build_and_post) + alice.participate_in_poll!(@status, @answer) + end + + it "creates a partcipation" do + lambda{ alice.participate_in_poll!(@status, @answer) }.should change(Participation, :count).by(1) + end + + it "creates the poll participation" do + lambda{ alice.participate_in_poll!(@status, @answer) }.should change(PollParticipation, :count).by(1) + end + it "sets the poll answer id" do - alice.participate_in_poll!(@status, 1).poll_answer.answer.should == "1" + alice.participate_in_poll!(@status, @answer).poll_answer.should == @answer end + end end \ No newline at end of file From c02414c36decded0016d54ed427caa1f1d03c332 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Fri, 21 Mar 2014 19:09:24 +0100 Subject: [PATCH 05/23] fixed wrong indenting and broken messages tab for polls --- app/assets/stylesheets/publisher.css.scss | 2 -- app/models/poll.rb | 2 +- app/models/poll_answer.rb | 4 ++-- app/models/poll_participation.rb | 2 +- spec/models/poll_participation_spec.rb | 20 ++++++++++---------- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/app/assets/stylesheets/publisher.css.scss b/app/assets/stylesheets/publisher.css.scss index 08ff3cec0..76bce5669 100644 --- a/app/assets/stylesheets/publisher.css.scss +++ b/app/assets/stylesheets/publisher.css.scss @@ -59,7 +59,6 @@ resize: none; height: 50px; } - } &.active textarea { min-height: 70px; @@ -79,7 +78,6 @@ line-height: 20px !important; width: 100% !important; } - } &.with_attachments .row-fluid#photodropzone_container { border-top: 1px dashed $border-grey; diff --git a/app/models/poll.rb b/app/models/poll.rb index 778f654ca..df01f127a 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -15,7 +15,7 @@ class Poll < ActiveRecord::Base validate :enough_poll_answers def enough_poll_answers - errors.add(:poll_answers, I18n.t("activerecord.errors.models.poll.attributes.poll_answers.not_enough_poll_answers")) if poll_answers.size < 2 + errors.add(:poll_answers, I18n.t("activerecord.errors.models.poll.attributes.poll_answers.not_enough_poll_answers")) if poll_answers.size < 2 end end diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb index 14ee658cf..46421266d 100644 --- a/app/models/poll_answer.rb +++ b/app/models/poll_answer.rb @@ -9,8 +9,8 @@ class PollAnswer < ActiveRecord::Base xml_attr :answer def update_vote_counter - self.vote_count = self.vote_count + 1 - self.save! + self.vote_count = self.vote_count + 1 + self.save! end end diff --git a/app/models/poll_participation.rb b/app/models/poll_participation.rb index c6c2ee85c..c666e5030 100644 --- a/app/models/poll_participation.rb +++ b/app/models/poll_participation.rb @@ -52,7 +52,7 @@ class PollParticipation < ActiveRecord::Base existing = PollParticipation.where(author_id: self.author.id, poll_id: self.poll.id) if existing.first != self and existing.count != 0 - self.errors.add(:poll, I18n.t("errors.models.poll_participations.attributes.poll.already_participated")) + self.errors.add(:poll, I18n.t("activerecord.errors.models.poll_participations.attributes.poll.already_participated")) end end diff --git a/spec/models/poll_participation_spec.rb b/spec/models/poll_participation_spec.rb index 26fbd10fc..c09ae06aa 100644 --- a/spec/models/poll_participation_spec.rb +++ b/spec/models/poll_participation_spec.rb @@ -29,7 +29,7 @@ describe PollParticipation do end - describe 'xml' do + describe 'xml' do before do @poll_participant = FactoryGirl.create(:user) @poll_participant_aspect = @poll_participant.aspects.create(:name => "bruisers") @@ -75,22 +75,22 @@ describe PollParticipation do end describe 'it is relayable' do - before do - @local_luke, @local_leia, @remote_raphael = set_up_friends - @remote_parent = FactoryGirl.build(:status_message_with_poll, :author => @remote_raphael) + before do + @local_luke, @local_leia, @remote_raphael = set_up_friends + @remote_parent = FactoryGirl.build(:status_message_with_poll, :author => @remote_raphael) - @local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first + @local_parent = @local_luke.post :status_message, :text => "hi", :to => @local_luke.aspects.first @poll2 = Poll.new(:question => 'Who is now in charge?') @poll2.poll_answers.build(:answer => "a") @poll2.poll_answers.build(:answer => "b") @local_parent.poll = @poll2 - @object_by_parent_author = @local_luke.participate_in_poll!(@local_parent, @poll2.poll_answers.first) - @object_by_recipient = @local_leia.participate_in_poll!(@local_parent, @poll2.poll_answers.first) - @dup_object_by_parent_author = @object_by_parent_author.dup + @object_by_parent_author = @local_luke.participate_in_poll!(@local_parent, @poll2.poll_answers.first) + @object_by_recipient = @local_leia.participate_in_poll!(@local_parent, @poll2.poll_answers.first) + @dup_object_by_parent_author = @object_by_parent_author.dup - @object_on_remote_parent = @local_luke.participate_in_poll!(@remote_parent, @remote_parent.poll.poll_answers.first) - end + @object_on_remote_parent = @local_luke.participate_in_poll!(@remote_parent, @remote_parent.poll.poll_answers.first) + end let(:build_object) { PollParticipation::Generator.new(alice, @status, @poll.poll_answers.first).build } it_should_behave_like 'it is relayable' From 95d98ff2b630a2fb314cfdad1bef187671fd518b Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Sat, 22 Mar 2014 15:36:17 +0100 Subject: [PATCH 06/23] improved code for poll participation --- app/models/poll_participation.rb | 9 +++------ spec/models/poll_participation_spec.rb | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/models/poll_participation.rb b/app/models/poll_participation.rb index c666e5030..3e1f7c368 100644 --- a/app/models/poll_participation.rb +++ b/app/models/poll_participation.rb @@ -46,17 +46,14 @@ class PollParticipation < ActiveRecord::Base end def not_already_participated - if self.poll == nil - return - end + return if poll.nil? - existing = PollParticipation.where(author_id: self.author.id, poll_id: self.poll.id) - if existing.first != self and existing.count != 0 + other_participations = PollParticipation.where(author_id: self.author.id, poll_id: self.poll.id).to_a-[self] + if other_participations.present? self.errors.add(:poll, I18n.t("activerecord.errors.models.poll_participations.attributes.poll.already_participated")) end end - class Generator < Federated::Generator def self.federated_class PollParticipation diff --git a/spec/models/poll_participation_spec.rb b/spec/models/poll_participation_spec.rb index c09ae06aa..951d14144 100644 --- a/spec/models/poll_participation_spec.rb +++ b/spec/models/poll_participation_spec.rb @@ -13,7 +13,7 @@ describe PollParticipation do end describe 'validation' do - it 'does forbid multiple participations in the same poll' do + it 'forbids multiple participations in the same poll' do expect { 2.times do |run| bob.participate_in_poll!(@status, @poll.poll_answers.first) @@ -21,7 +21,7 @@ describe PollParticipation do }.to raise_error end - it 'does allow a one time participation in a poll' do + it 'allows a one time participation in a poll' do expect { bob.participate_in_poll!(@status, @poll.poll_answers.first) }.to_not raise_error From 18a43295b73555528f489269498d8047b5070703 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Sun, 23 Mar 2014 16:53:28 +0100 Subject: [PATCH 07/23] poll form completed --- .../javascripts/app/views/publisher_view.js | 24 +++++++++++---- .../stylesheets/publisher_blueprint.css.scss | 30 ++++++++++++++++++- .../publisher/_publisher_blueprint.html.haml | 17 ++++++----- config/locales/diaspora/en.yml | 7 +++-- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 10f01896b..ae60f0376 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -32,6 +32,7 @@ app.views.Publisher = Backbone.View.extend({ initialize : function(opts){ this.standalone = opts ? opts.standalone : false; + this.option_counter = 1; // init shortcut references to the various elements this.el_input = this.$('#status_message_fake_text'); @@ -182,16 +183,29 @@ app.views.Publisher = Backbone.View.extend({ }, addPollAnswer: function(){ + if($(".poll_answer").size() == 1) { + $(".remove_poll_answer").css("visibility","visible"); + } + + this.option_counter++; var clone = this.el_poll_answer.clone(); - var count_of_answers = $('.poll_answer_input').size()+1; - clone.children('.poll_answer_input').attr("name", "poll_answer_"+count_of_answers); - this.el_poll_answer.last().after(clone); + + var answer = clone.find('.poll_answer_input'); + answer.attr("name", "poll_answer_" + this.option_counter); + + var placeholder = answer.attr("placeholder"); + var expression = /[^0-9]+/; + answer.attr("placeholder", expression.exec(placeholder) + this.option_counter); + + $('#poll_creator_wrapper .poll_answer').last().after(clone); }, removePollAnswer: function(evt){ - if($(".poll_answer_input").size() > 1) { - $(evt.target).parent().remove(); + $(evt.target).parent().remove(); + if($(".poll_answer").size() == 1) { + $(".remove_poll_answer").css("visibility","hidden");; } + return false; }, // avoid submitting form when pressing Enter key diff --git a/app/assets/stylesheets/publisher_blueprint.css.scss b/app/assets/stylesheets/publisher_blueprint.css.scss index 879917660..e01fef626 100644 --- a/app/assets/stylesheets/publisher_blueprint.css.scss +++ b/app/assets/stylesheets/publisher_blueprint.css.scss @@ -324,8 +324,36 @@ display:none; border: 1px solid $border-dark-grey; padding:5px; + @include border-radius(2px); } .remove_poll_answer { - display:inline; + visibility:hidden; + float:right; + display: table-cell; } + +.poll_answer_input { + width:100%; +} + +#add_poll_answer_wrapper { + padding:5px 0 5px 0; + display:block; +} + +#poll_question { + width: 100%; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +.poll_answer { + display: table; + width: 100%; +} + +.poll_answer_input_wrapper { + display: table-cell; +} \ No newline at end of file diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index b5eb1936f..a34e10893 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -38,15 +38,16 @@ #location_container %br #poll_creator_wrapper - = 'Poll creation' - %br - %input{:id => 'poll_question', :placeholder => 'Question', :name => 'poll_question', :class => 'span-12'} - %div{:class => 'poll_answer span-12'} - %input{:class => 'poll_answer_input span-8', :placeholder => 'Answer', :name => 'poll_answer_1'} - %a{:class => 'remove_poll_answer span-3'} + = t('shared.publisher.poll.add_a_poll') + %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question'} + .poll_answer + %span{:class => 'poll_answer_input_wrapper'} + %input{:class => 'poll_answer_input', :placeholder => t('shared.publisher.poll.option'), :name => 'poll_answer_1'} + %a{:class => 'remove_poll_answer'} = t('shared.publisher.poll.remove_poll_answer') - %div{:id => 'add_poll_answer', :class => 'button creation'} - = t('shared.publisher.poll.add_poll_answer') + #add_poll_answer_wrapper + #add_poll_answer{:class => 'button creation'} + = t('shared.publisher.poll.add_poll_answer') - if publisher_public = hidden_field_tag 'aspect_ids[]', "public" diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 2f36c7c38..ed21bf4c9 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -1046,8 +1046,11 @@ en: i_like: "I'm interested in %{tags}. " invited_by: "Thanks for the invite, " poll: - remove_poll_answer: "Remove answer" - add_poll_answer: "Add answer" + remove_poll_answer: "Remove option" + add_poll_answer: "Add option" + add_a_poll: "Add a poll" + question: "Question" + option: "Option 1" add_contact: enter_a_diaspora_username: "Enter a diaspora* username:" your_diaspora_username_is: "Your diaspora* username is: %{diaspora_handle}" From 04199837b3eef45c02789e02e4dd45a16f54d9d3 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Sun, 23 Mar 2014 20:38:12 +0100 Subject: [PATCH 08/23] poll creation done --- app/assets/images/icons/poll.png | Bin 0 -> 187 bytes .../javascripts/app/views/publisher_view.js | 7 ++++--- app/controllers/status_messages_controller.rb | 13 +++++++++---- app/models/status_message.rb | 3 ++- .../publisher/_publisher_blueprint.html.haml | 4 ++-- 5 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 app/assets/images/icons/poll.png diff --git a/app/assets/images/icons/poll.png b/app/assets/images/icons/poll.png new file mode 100644 index 0000000000000000000000000000000000000000..026a12a2b28c952e0df0159fd73bbf66b8dbbb84 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^qChOj!3HFa+MYK6DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5Xd_7$pLn>}1{rUgjo_Qa;gO}jPb&8J ix%|s8Yh`F)U}lher}N)Cdt)=uU params[:location_address], :coordinates => params[:location_coords]) if params[:location_address].present? @status_message.build_poll(:question => params[:poll_question]) if params[:poll_question].present? - - #save all answers for poll - + poll_answers = params[:poll_answers] + if params[:poll_answers].instance_of? String + poll_answers = [params[:poll_answers]] + end + + poll_answers.each do |poll_answer| + @status_message.poll.poll_answers.build(:answer => poll_answer) + end @status_message.attach_photos_by_ids(params[:photos]) @@ -83,7 +88,7 @@ class StatusMessagesController < ApplicationController respond_to do |format| format.html { redirect_to :back } format.mobile { redirect_to stream_path } - format.json { render :nothing => true , :status => 403 } + format.json { render {:nothing => true} , :status => 403 } end end end diff --git a/app/models/status_message.rb b/app/models/status_message.rb index aa79c69f7..6e73ecb48 100644 --- a/app/models/status_message.rb +++ b/app/models/status_message.rb @@ -25,7 +25,8 @@ class StatusMessage < Post has_many :photos, :dependent => :destroy, :foreign_key => :status_message_guid, :primary_key => :guid has_one :location - has_one :poll + has_one :poll, autosave: true + # a StatusMessage is federated before its photos are so presence_of_content() fails erroneously if no text is present # therefore, we put the validation in a before_destory callback instead of a validation diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index a34e10893..daefa53c2 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -29,7 +29,7 @@ %span.markdownIndications != t('shared.publisher.formatWithMarkdown', markdown_link: link_to(t('help.markdown'), 'https://diasporafoundation.org/formatting', target: :blank)) #poll_creator.btn{:title => t('.create_poll')} - = image_tag 'icons/marker.png', :alt => t('.create_poll').titleize, :class => 'publisher_image' + = image_tag 'icons/poll.png', :alt => t('.create_poll').titleize, :class => 'publisher_image' #locator.btn{:title => t('shared.publisher.get_location')} = image_tag 'icons/marker.png', :alt => t('shared.publisher.get_location').titleize, :class => 'publisher_image' #file-upload.btn{:title => t('shared.publisher.upload_photos')} @@ -42,7 +42,7 @@ %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question'} .poll_answer %span{:class => 'poll_answer_input_wrapper'} - %input{:class => 'poll_answer_input', :placeholder => t('shared.publisher.poll.option'), :name => 'poll_answer_1'} + %input{:class => 'poll_answer_input', :placeholder => t('shared.publisher.poll.option'), :name => 'poll_answers[]'} %a{:class => 'remove_poll_answer'} = t('shared.publisher.poll.remove_poll_answer') #add_poll_answer_wrapper From d0a77ce6b3a9a0cefa1fc04c9caa665595ba569f Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Mon, 24 Mar 2014 19:43:52 +0100 Subject: [PATCH 09/23] design for poll participation implemented, saving works as well --- .../app/models/poll_participation.js | 5 ++ .../javascripts/app/models/status_message.js | 3 +- app/assets/javascripts/app/views/poll.js | 50 +++++++++++++++++++ .../javascripts/app/views/publisher_view.js | 2 +- .../app/views/stream_post_views.js | 2 + app/assets/stylesheets/application.css.sass | 1 + app/assets/stylesheets/poll.css.scss | 43 ++++++++++++++++ app/assets/templates/poll_tpl.jst.hbs | 19 +++++++ .../templates/status-message_tpl.jst.hbs | 1 + .../poll_participations_controller.rb | 30 +++++++++++ app/controllers/status_messages_controller.rb | 20 ++++---- app/models/poll.rb | 18 +++++++ app/models/poll_answer.rb | 2 + app/models/post.rb | 3 ++ app/presenters/post_presenter.rb | 1 + config/locales/javascript/javascript.en.yml | 4 ++ config/routes.rb | 4 ++ lib/federated/generator.rb | 2 - 18 files changed, 197 insertions(+), 13 deletions(-) create mode 100644 app/assets/javascripts/app/models/poll_participation.js create mode 100644 app/assets/javascripts/app/views/poll.js create mode 100644 app/assets/stylesheets/poll.css.scss create mode 100644 app/assets/templates/poll_tpl.jst.hbs create mode 100644 app/controllers/poll_participations_controller.rb diff --git a/app/assets/javascripts/app/models/poll_participation.js b/app/assets/javascripts/app/models/poll_participation.js new file mode 100644 index 000000000..a31c35779 --- /dev/null +++ b/app/assets/javascripts/app/models/poll_participation.js @@ -0,0 +1,5 @@ +app.models.PollParticipation = Backbone.Model.extend({ + url : function(){ + "/poll_participations" + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/app/models/status_message.js b/app/assets/javascripts/app/models/status_message.js index 07f8f2f53..bce96553d 100644 --- a/app/assets/javascripts/app/models/status_message.js +++ b/app/assets/javascripts/app/models/status_message.js @@ -13,7 +13,8 @@ app.models.StatusMessage = app.models.Post.extend({ status_message : _.clone(this.attributes), aspect_ids : this.get("aspect_ids"), photos : this.photos && this.photos.pluck("id"), - services : this.get("services") + services : this.get("services"), + poll : this.get("poll") } } }); diff --git a/app/assets/javascripts/app/views/poll.js b/app/assets/javascripts/app/views/poll.js new file mode 100644 index 000000000..c7f9ebaab --- /dev/null +++ b/app/assets/javascripts/app/views/poll.js @@ -0,0 +1,50 @@ +app.views.Poll = app.views.Base.extend({ + templateName : "poll", + + events : { + "click .submit" : "vote" + }, + + initialize : function(options) { + this.poll = this.model.attributes.poll; + this.progressBarFactor = 3; + //this.model.bind('remove', this.remove, this); + }, + + postRenderTemplate : function() { + if(this.poll) { + this.setProgressBar(); + } + }, + + setProgressBar : function() { + var answers = this.poll.poll_answers; + for(index = 0; index < answers.length; ++index) { + var percentage = 0; + if(this.poll.participation_count != 0) { + percentage = answers[index].vote_count / this.poll.participation_count * 100; + } + var input = this.$("input[value="+answers[index].id+"]"); + var progressBar = $(input).parent().find(".poll_progress_bar"); + var width = percentage * this.progressBarFactor; + progressBar.css("width", width + "px"); + } + // + }, + + vote : function(evt){ + var result = parseInt($(evt.target).parent().find("input[name=vote]:checked").val()); + var pollParticipation = new app.models.PollParticipation(); + pollParticipation.save({ + "poll_answer_id" : result, + "poll_id" : this.poll.poll_id, + },{ + url : "/posts/"+this.poll.post_id+"/poll_participations", + success : function() { + console.log(success); + //todo remove radios+input + } + }); + } + +}); \ No newline at end of file diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 4f020d7f7..dc51575a9 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -192,7 +192,7 @@ app.views.Publisher = Backbone.View.extend({ var clone = this.el_poll_answer.clone(); var answer = clone.find('.poll_answer_input'); - //answer.attr("name", "poll_answer_" + this.option_counter); + answer.val(""); var placeholder = answer.attr("placeholder"); var expression = /[^0-9]+/; diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js index d8a9551e0..fb1d846d4 100644 --- a/app/assets/javascripts/app/views/stream_post_views.js +++ b/app/assets/javascripts/app/views/stream_post_views.js @@ -9,6 +9,7 @@ app.views.StreamPost = app.views.Post.extend({ ".post-content" : "postContentView", ".oembed" : "oEmbedView", ".opengraph" : "openGraphView", + ".poll" : "pollView", ".status-message-location" : "postLocationStreamView" }, @@ -31,6 +32,7 @@ app.views.StreamPost = app.views.Post.extend({ this.commentStreamView = new app.views.CommentStream({model : this.model}); this.oEmbedView = new app.views.OEmbed({model : this.model}); this.openGraphView = new app.views.OpenGraph({model : this.model}); + this.pollView = new app.views.Poll({model : this.model}); }, diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass index c0555449e..08b7a445b 100644 --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -10,6 +10,7 @@ @import 'header' @import 'footer' @import 'opengraph' +@import 'poll' @import 'help' @import 'profile' @import 'publisher_blueprint' diff --git a/app/assets/stylesheets/poll.css.scss b/app/assets/stylesheets/poll.css.scss new file mode 100644 index 000000000..913bd69be --- /dev/null +++ b/app/assets/stylesheets/poll.css.scss @@ -0,0 +1,43 @@ +.poll_form { + display: block; + margin: 10px 0px 10px 0px; + border-top: solid 1px $border-grey; + border-bottom: solid 1px $border-grey; + padding: 10px 0px 5px 0px; + overflow: hidden; + width: 100%; +} + +.poll_form input[type="radio"] { + display:inline !important; +} + +.poll_result { + width:100%px; + display:inline; +} + +.poll_progress_bar { + position:absolute; + width:100px; + height:15px; + top:-10px; + z-index:-1; + background-color:#3f8fba; +} + +.poll_statistic{ + float:right; +} + +.poll_progress_bar_wrapper { + position: relative; + width: 0; + height: 0; + display:inline-block; +} + +.poll_answer_entry{ + display:inline; + width:100%; +} diff --git a/app/assets/templates/poll_tpl.jst.hbs b/app/assets/templates/poll_tpl.jst.hbs new file mode 100644 index 000000000..6cac9b4d2 --- /dev/null +++ b/app/assets/templates/poll_tpl.jst.hbs @@ -0,0 +1,19 @@ +{{#if poll}} +
+

{{t "poll.result" votes=poll.participation_count}}

+ {{poll.question}}
+ {{#poll.poll_answers}} +
+ +
+
+
+
+ {{answer}} +
+
+
+ {{/poll.poll_answers}} + +
+{{/if}} \ No newline at end of file diff --git a/app/assets/templates/status-message_tpl.jst.hbs b/app/assets/templates/status-message_tpl.jst.hbs index 166c8cb1d..761dc57c6 100644 --- a/app/assets/templates/status-message_tpl.jst.hbs +++ b/app/assets/templates/status-message_tpl.jst.hbs @@ -18,4 +18,5 @@ {{{text}}}
+
diff --git a/app/controllers/poll_participations_controller.rb b/app/controllers/poll_participations_controller.rb new file mode 100644 index 000000000..b2d435bb8 --- /dev/null +++ b/app/controllers/poll_participations_controller.rb @@ -0,0 +1,30 @@ +class PollParticipationsController < ApplicationController + include ApplicationHelper + before_filter :authenticate_user! + + def create + answer = PollAnswer.find(params[:poll_answer_id]) + poll_participation = current_user.participate_in_poll!(target, answer) if target rescue ActiveRecord::RecordInvalid + if poll_participation + respond_to do |format| + format.html { redirect_to :back } + format.mobile { redirect_to stream_path } + format.json { render :nothing => true, :status => 201 } + end + else + respond_to do |format| + format.html { redirect_to :back } + format.mobile { redirect_to stream_path } + format.json { render :nothing => true, :status => 403 } + end + end + end + + private + + def target + @target ||= if params[:post_id] + current_user.find_visible_shareable_by_id(Post, params[:post_id]) || raise(ActiveRecord::RecordNotFound.new) + end + end +end \ No newline at end of file diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index 1a083d31c..c2b2e2508 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -49,16 +49,18 @@ class StatusMessagesController < ApplicationController @status_message = current_user.build_post(:status_message, params[:status_message]) @status_message.build_location(:address => params[:location_address], :coordinates => params[:location_coords]) if params[:location_address].present? - @status_message.build_poll(:question => params[:poll_question]) if params[:poll_question].present? - poll_answers = params[:poll_answers] - if params[:poll_answers].instance_of? String - poll_answers = [params[:poll_answers]] - end - - poll_answers.each do |poll_answer| - @status_message.poll.poll_answers.build(:answer => poll_answer) + if params[:poll_question].present? + @status_message.build_poll(:question => params[:poll_question]) + poll_answers = params[:poll_answers] + if params[:poll_answers].instance_of? String + poll_answers = [params[:poll_answers]] + end + poll_answers.each do |poll_answer| + @status_message.poll.poll_answers.build(:answer => poll_answer) + end end + @status_message.attach_photos_by_ids(params[:photos]) if @status_message.save @@ -88,7 +90,7 @@ class StatusMessagesController < ApplicationController respond_to do |format| format.html { redirect_to :back } format.mobile { redirect_to stream_path } - format.json { render {:nothing => true} , :status => 403 } + format.json { render :nothing => true, :status => 403 } end end end diff --git a/app/models/poll.rb b/app/models/poll.rb index df01f127a..1450701b4 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -14,8 +14,26 @@ class Poll < ActiveRecord::Base validate :enough_poll_answers + #TODO check if user has the right to vote + + self.include_root_in_json = false + def enough_poll_answers errors.add(:poll_answers, I18n.t("activerecord.errors.models.poll.attributes.poll_answers.not_enough_poll_answers")) if poll_answers.size < 2 end + def as_json(options={}) + { + :poll_id => self.id, + :post_id => self.status_message.id, + :question => self.question, + :poll_answers => self.poll_answers, + :participation_count => self.participation_count + #TODO already participated? + } + end + + def participation_count + poll_answers.sum("vote_count") + end end diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb index 46421266d..8c8de154b 100644 --- a/app/models/poll_answer.rb +++ b/app/models/poll_answer.rb @@ -8,6 +8,8 @@ class PollAnswer < ActiveRecord::Base xml_attr :answer + self.include_root_in_json = false + def update_vote_counter self.vote_count = self.vote_count + 1 self.save! diff --git a/app/models/post.rb b/app/models/post.rb index b2eda3d06..0cbc9f07d 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -72,6 +72,9 @@ class Post < ActiveRecord::Base def address end + def poll + end + def self.excluding_blocks(user) people = user.blocks.map{|b| b.person_id} scope = scoped diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index fa179250a..7e0d4789d 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -35,6 +35,7 @@ class PostPresenter :root => root, :title => title, :address => @post.address, + :poll => @post.poll, :interactions => { :likes => [user_like].compact, diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index 0cf179ba4..ac6fd0bf8 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -172,3 +172,7 @@ en: reshared: "Reshared" comment: "Comment" home: "HOME" + + poll: + vote: "Vote" + result: "<%=votes%> votes so far" diff --git a/config/routes.rb b/config/routes.rb index 38405a721..39b66432e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,11 +31,15 @@ Diaspora::Application.routes.draw do get :interactions end + resources :poll_participations, :only => [:create] + resources :likes, :only => [:create, :destroy, :index ] resources :participations, :only => [:create, :destroy, :index] resources :comments, :only => [:new, :create, :destroy, :index] end + + get 'p/:id' => 'posts#show', :as => 'short_post' get 'posts/:id/iframe' => 'posts#iframe', :as => 'iframe' diff --git a/lib/federated/generator.rb b/lib/federated/generator.rb index 96fe9006c..ab6025ef2 100644 --- a/lib/federated/generator.rb +++ b/lib/federated/generator.rb @@ -11,8 +11,6 @@ module Federated FEDERATION_LOGGER.info("user:#{@user.id} dispatching #{relayable.class}:#{relayable.guid}") Postzord::Dispatcher.defer_build_and_post(@user, relayable) relayable - else - false end end From e4c68a4edb7efc66222c215066e847099f652c85 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Mon, 24 Mar 2014 19:52:56 +0100 Subject: [PATCH 10/23] improved status messages controller code --- app/controllers/status_messages_controller.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index c2b2e2508..4ed6dd531 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -51,11 +51,7 @@ class StatusMessagesController < ApplicationController @status_message.build_location(:address => params[:location_address], :coordinates => params[:location_coords]) if params[:location_address].present? if params[:poll_question].present? @status_message.build_poll(:question => params[:poll_question]) - poll_answers = params[:poll_answers] - if params[:poll_answers].instance_of? String - poll_answers = [params[:poll_answers]] - end - poll_answers.each do |poll_answer| + [*params[:poll_answers]].each do |poll_answer| @status_message.poll.poll_answers.build(:answer => poll_answer) end end @@ -129,4 +125,4 @@ class StatusMessagesController < ApplicationController def remove_getting_started current_user.disable_getting_started end -end +end \ No newline at end of file From 12fabe2fb9d706880598bc9f87deade186ef7f25 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Tue, 25 Mar 2014 15:59:10 +0100 Subject: [PATCH 11/23] finalized voting design + some design fixes + improved code --- app/assets/images/icons/poll.png | Bin 187 -> 0 bytes app/assets/javascripts/app/views/poll.js | 47 +++++++++++++++--- .../javascripts/app/views/publisher_view.js | 4 +- app/assets/stylesheets/poll.css.scss | 10 ++-- .../stylesheets/publisher_blueprint.css.scss | 13 ++++- app/assets/templates/poll_tpl.jst.hbs | 35 +++++++++---- .../poll_participations_controller.rb | 10 ++-- app/models/poll.rb | 9 ++-- app/presenters/post_presenter.rb | 11 +++- .../publisher/_publisher_blueprint.html.haml | 10 ++-- config/locales/javascript/javascript.en.yml | 4 +- 11 files changed, 112 insertions(+), 41 deletions(-) delete mode 100644 app/assets/images/icons/poll.png diff --git a/app/assets/images/icons/poll.png b/app/assets/images/icons/poll.png deleted file mode 100644 index 026a12a2b28c952e0df0159fd73bbf66b8dbbb84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^qChOj!3HFa+MYK6DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5Xd_7$pLn>}1{rUgjo_Qa;gO}jPb&8J ix%|s8Yh`F)U}lher}N)Cdt)=uU -

{{t "poll.result" votes=poll.participation_count}}

+

{{t "poll.count" votes=poll.participation_count}}

{{poll.question}}
- {{#poll.poll_answers}} -
- -
+ {{#unless already_participated_in_poll}} +
+ {{#poll.poll_answers}} + + {{answer}} +
+ {{/poll.poll_answers}} + +
+

+
{{t "poll.toggle_result"}}
+

+ {{/unless}} +
+
{{t "poll.result"}}
+ {{#poll.poll_answers}} +
-
+
{{answer}} -
-
-
- {{/poll.poll_answers}} - +

+
+ {{/poll.poll_answers}} +
+ {{/if}} \ No newline at end of file diff --git a/app/controllers/poll_participations_controller.rb b/app/controllers/poll_participations_controller.rb index b2d435bb8..89f6854f5 100644 --- a/app/controllers/poll_participations_controller.rb +++ b/app/controllers/poll_participations_controller.rb @@ -3,15 +3,15 @@ class PollParticipationsController < ApplicationController before_filter :authenticate_user! def create - answer = PollAnswer.find(params[:poll_answer_id]) - poll_participation = current_user.participate_in_poll!(target, answer) if target rescue ActiveRecord::RecordInvalid - if poll_participation + begin + answer = PollAnswer.find(params[:poll_answer_id]) + poll_participation = current_user.participate_in_poll!(target, answer) if target respond_to do |format| format.html { redirect_to :back } format.mobile { redirect_to stream_path } - format.json { render :nothing => true, :status => 201 } + format.json { render json: poll_participation, :status => 201 } end - else + rescue ActiveRecord::RecordInvalid respond_to do |format| format.html { redirect_to :back } format.mobile { redirect_to stream_path } diff --git a/app/models/poll.rb b/app/models/poll.rb index 1450701b4..d43fcec77 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -13,8 +13,6 @@ class Poll < ActiveRecord::Base delegate :author, :author_id, :public?, :subscribers, to: :status_message validate :enough_poll_answers - - #TODO check if user has the right to vote self.include_root_in_json = false @@ -28,12 +26,15 @@ class Poll < ActiveRecord::Base :post_id => self.status_message.id, :question => self.question, :poll_answers => self.poll_answers, - :participation_count => self.participation_count - #TODO already participated? + :participation_count => self.participation_count, } end def participation_count poll_answers.sum("vote_count") end + + def already_participated?(user) + poll_participations.where(:author_id => user.person.id).present? + end end diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index 7e0d4789d..d797da86c 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -35,7 +35,8 @@ class PostPresenter :root => root, :title => title, :address => @post.address, - :poll => @post.poll, + :poll => @post.poll(), + :already_participated_in_poll => already_participated_in_poll, :interactions => { :likes => [user_like].compact, @@ -73,6 +74,14 @@ class PostPresenter @current_user.present? end + private + + def already_participated_in_poll + if @post.poll + @post.poll.already_participated?(current_user) + end + end + end class PostInteractionPresenter diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index daefa53c2..f12881770 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -28,8 +28,7 @@ %span#publisher-images %span.markdownIndications != t('shared.publisher.formatWithMarkdown', markdown_link: link_to(t('help.markdown'), 'https://diasporafoundation.org/formatting', target: :blank)) - #poll_creator.btn{:title => t('.create_poll')} - = image_tag 'icons/poll.png', :alt => t('.create_poll').titleize, :class => 'publisher_image' + %a{:id => "poll_creator", :href => "#", :class => "entypo bar-graph gray small publisher_image"} #locator.btn{:title => t('shared.publisher.get_location')} = image_tag 'icons/marker.png', :alt => t('shared.publisher.get_location').titleize, :class => 'publisher_image' #file-upload.btn{:title => t('shared.publisher.upload_photos')} @@ -39,12 +38,13 @@ %br #poll_creator_wrapper = t('shared.publisher.poll.add_a_poll') - %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question'} + #poll_question_wrapper + %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question'} .poll_answer %span{:class => 'poll_answer_input_wrapper'} %input{:class => 'poll_answer_input', :placeholder => t('shared.publisher.poll.option'), :name => 'poll_answers[]'} - %a{:class => 'remove_poll_answer'} - = t('shared.publisher.poll.remove_poll_answer') + %a{:class => 'remove_poll_answer', :title => t('shared.publisher.poll.remove_poll_answer')} + .icons-deletelabel #add_poll_answer_wrapper #add_poll_answer{:class => 'button creation'} = t('shared.publisher.poll.add_poll_answer') diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index ac6fd0bf8..4f6f09424 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -175,4 +175,6 @@ en: poll: vote: "Vote" - result: "<%=votes%> votes so far" + result: "Result" + count: "<%=votes%> votes so far" + toggle_result: "Toggle result" \ No newline at end of file From c484b2cd0c0759da82da58a92f009d9e8988ad2a Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Wed, 26 Mar 2014 18:45:49 +0100 Subject: [PATCH 12/23] fixed poll icon issue, improved code, poll in bookmarklets now available --- app/assets/javascripts/app/views/poll.js | 1 - .../javascripts/app/views/publisher_view.js | 2 +- app/assets/stylesheets/publisher.css.scss | 8 +++++- .../stylesheets/publisher_blueprint.css.scss | 19 +++++++++++--- .../poll_participations_controller.rb | 26 +++++++++---------- app/views/publisher/_publisher.mobile.haml | 2 +- .../publisher/_publisher_blueprint.html.haml | 4 ++- .../publisher/_publisher_bootstrap.html.haml | 13 ++++++++++ 8 files changed, 53 insertions(+), 22 deletions(-) diff --git a/app/assets/javascripts/app/views/poll.js b/app/assets/javascripts/app/views/poll.js index 31fa48379..7d3691eb2 100644 --- a/app/assets/javascripts/app/views/poll.js +++ b/app/assets/javascripts/app/views/poll.js @@ -9,7 +9,6 @@ app.views.Poll = app.views.Base.extend({ initialize : function(options) { this.poll = this.model.attributes.poll; this.progressBarFactor = 3; - //this.model.bind('remove', this.remove, this); }, postRenderTemplate : function() { diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index b8062347e..b2c58e4c7 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -202,7 +202,7 @@ app.views.Publisher = Backbone.View.extend({ }, removePollAnswer: function(evt){ - $(evt.target).parents().eq(1).remove(); + $(evt.currentTarget).parent().remove(); if($(".poll_answer").size() == 1) { $(".remove_poll_answer").css("visibility","hidden");; } diff --git a/app/assets/stylesheets/publisher.css.scss b/app/assets/stylesheets/publisher.css.scss index 76bce5669..bdb835dca 100644 --- a/app/assets/stylesheets/publisher.css.scss +++ b/app/assets/stylesheets/publisher.css.scss @@ -82,6 +82,13 @@ &.with_attachments .row-fluid#photodropzone_container { border-top: 1px dashed $border-grey; } + + #poll_creator_wrapper { + display:none; + border-top: 1px dashed $border-grey; + padding:4px 6px 4px 6px; + } + &.with_location .row-fluid#location_container { height: 30px; #hide_location { display: none !important; } @@ -216,4 +223,3 @@ } } } - diff --git a/app/assets/stylesheets/publisher_blueprint.css.scss b/app/assets/stylesheets/publisher_blueprint.css.scss index f4cb7171f..d252f0578 100644 --- a/app/assets/stylesheets/publisher_blueprint.css.scss +++ b/app/assets/stylesheets/publisher_blueprint.css.scss @@ -310,9 +310,22 @@ } } #poll_creator { - @extend #locator; - right: 60px; - margin-bottom:-5px; + bottom: 1px !important; + display: inline-block; + margin: 0; + cursor: pointer; + position: absolute !important; + right: 55px; + i { + @include opacity(0.4); + } + &:hover { + color: $text-dark-grey; + cursor: pointer; + i { + @include opacity(1); + } + } } .btn { diff --git a/app/controllers/poll_participations_controller.rb b/app/controllers/poll_participations_controller.rb index 89f6854f5..2fd07c76e 100644 --- a/app/controllers/poll_participations_controller.rb +++ b/app/controllers/poll_participations_controller.rb @@ -3,20 +3,18 @@ class PollParticipationsController < ApplicationController before_filter :authenticate_user! def create - begin - answer = PollAnswer.find(params[:poll_answer_id]) - poll_participation = current_user.participate_in_poll!(target, answer) if target - respond_to do |format| - format.html { redirect_to :back } - format.mobile { redirect_to stream_path } - format.json { render json: poll_participation, :status => 201 } - end - rescue ActiveRecord::RecordInvalid - respond_to do |format| - format.html { redirect_to :back } - format.mobile { redirect_to stream_path } - format.json { render :nothing => true, :status => 403 } - end + answer = PollAnswer.find(params[:poll_answer_id]) + poll_participation = current_user.participate_in_poll!(target, answer) if target + respond_to do |format| + format.html { redirect_to :back } + format.mobile { redirect_to stream_path } + format.json { render json: poll_participation, :status => 201 } + end + rescue ActiveRecord::RecordInvalid + respond_to do |format| + format.html { redirect_to :back } + format.mobile { redirect_to stream_path } + format.json { render :nothing => true, :status => 403 } end end diff --git a/app/views/publisher/_publisher.mobile.haml b/app/views/publisher/_publisher.mobile.haml index a1556a32c..dca0f8cf2 100644 --- a/app/views/publisher/_publisher.mobile.haml +++ b/app/views/publisher/_publisher.mobile.haml @@ -39,4 +39,4 @@ #publisher_mobile = submit_tag t('shared.publisher.share'), :class => 'btn primary', :id => "submit_new_message" - #publisher_photo_upload + #publisher_photo_upload \ No newline at end of file diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index f12881770..cccf338d6 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -28,7 +28,9 @@ %span#publisher-images %span.markdownIndications != t('shared.publisher.formatWithMarkdown', markdown_link: link_to(t('help.markdown'), 'https://diasporafoundation.org/formatting', target: :blank)) - %a{:id => "poll_creator", :href => "#", :class => "entypo bar-graph gray small publisher_image"} + #poll_creator.btn{:title => t('shared.publisher.poll.add_a_poll')} + %i.entypo.bar-graph{:class => "publisher_image"} + #locator.btn{:title => t('shared.publisher.get_location')} = image_tag 'icons/marker.png', :alt => t('shared.publisher.get_location').titleize, :class => 'publisher_image' #file-upload.btn{:title => t('shared.publisher.upload_photos')} diff --git a/app/views/publisher/_publisher_bootstrap.html.haml b/app/views/publisher/_publisher_bootstrap.html.haml index 9df147931..103c53d5a 100644 --- a/app/views/publisher/_publisher_bootstrap.html.haml +++ b/app/views/publisher/_publisher_bootstrap.html.haml @@ -22,8 +22,21 @@ %ul#photodropzone .row-fluid#location_container = hidden_field :location, :coords + .row-fluid#poll_creator_wrapper + = t('shared.publisher.poll.add_a_poll') + #poll_question_wrapper{:class => "input-block-level"} + %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question', :class=> "form-control"} + .poll_answer + %input{:class => 'form-control poll_answer_input', :placeholder => t('shared.publisher.poll.option'), :name => 'poll_answers[]'} + .remove_poll_answer.btn.btn-link{:title => t('shared.publisher.poll.remove_poll_answer')} + %i.entypo.trash + #add_poll_answer_wrapper + #add_poll_answer{:class => 'btn btn-default'} + = t('shared.publisher.poll.add_poll_answer') .row-fluid#button_container #publisher-images.pull-right + #poll_creator.btn.btn-link{:title => t('shared.publisher.poll.add_a_poll')} + %i.entypo.bar-graph #file-upload.btn.btn-link{:title => t('shared.publisher.upload_photos')} %i.entypo.camera.publisher_image #locator.btn.btn-link{:title => t('shared.publisher.get_location')} From 9c24365fde4bff7bd51f18c1386a5929c06ed440 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Wed, 26 Mar 2014 20:24:48 +0100 Subject: [PATCH 13/23] changed poll result + some minor text improvements --- app/assets/javascripts/app/views/poll.js | 35 ++++++++++++++------- app/assets/stylesheets/poll.css.scss | 2 +- app/assets/templates/poll_tpl.jst.hbs | 30 +++++++++--------- config/locales/javascript/javascript.en.yml | 7 +++-- 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/app/assets/javascripts/app/views/poll.js b/app/assets/javascripts/app/views/poll.js index 7d3691eb2..b16fd8706 100644 --- a/app/assets/javascripts/app/views/poll.js +++ b/app/assets/javascripts/app/views/poll.js @@ -9,19 +9,21 @@ app.views.Poll = app.views.Base.extend({ initialize : function(options) { this.poll = this.model.attributes.poll; this.progressBarFactor = 3; + this.toggleMode = 0; }, postRenderTemplate : function() { if(this.poll) { this.setProgressBar(); - this.hideResult(); } }, - hideResult : function() { - if(!this.model.attributes.already_participated_in_poll) { - this.$('.poll_result').hide(); - } + removeForm : function() { + var cnt = this.$("form").contents(); + this.$("form").replaceWith(cnt); + this.$('input').remove(); + this.$('submit').remove(); + this.$('.toggle_result_wrapper').remove(); }, setProgressBar : function() { @@ -32,14 +34,23 @@ app.views.Poll = app.views.Base.extend({ percentage = answers[index].vote_count / this.poll.participation_count * 100; } var progressBar = this.$(".poll_progress_bar[data-answerid="+answers[index].id+"]"); - progressBar.parents().eq(1).find(".percentage").html(" - " + percentage + "%"); + progressBar.parent().next().html(" - " + percentage + "%"); var width = percentage * this.progressBarFactor; progressBar.css("width", width + "px"); } }, toggleResult : function(e) { - $('.poll_result').toggle(); + this.$('.poll_progress_bar_wrapper').toggle(); + this.$('.percentage').toggle(); + if(this.toggleMode == 0) { + this.$('.toggle_result').html(Diaspora.I18n.t("poll.close_result")); + this.toggleMode = 1; + }else{ + this.$('.toggle_result').html(Diaspora.I18n.t("poll.show_result")); + this.toggleStringMode = 0; + } + return false; }, @@ -50,7 +61,7 @@ app.views.Poll = app.views.Base.extend({ updateCounter : function(answerId) { this.poll.participation_count++; - this.$('.poll_statistic').html(Diaspora.I18n.t("poll.count", {"votes" : this.poll.participation_count})); + this.$('.poll_statistic').html(Diaspora.I18n.t("poll.count", {"count" : this.poll.participation_count})); var answers = this.poll.poll_answers; for(index = 0; index < answers.length; ++index) { if(answers[index].id == answerId) { @@ -70,10 +81,12 @@ app.views.Poll = app.views.Base.extend({ },{ url : "/posts/"+this.poll.post_id+"/poll_participations", success : function(model, response) { - parent.$('.poll_form form').remove(); - parent.$('.toggle_result_wrapper').remove(); - parent.$('.poll_result').show(); + parent.removeForm(); parent.refreshResult(result); + if(parent.toggleMode == 0) { + parent.toggleResult(null); + } + } }); return false; diff --git a/app/assets/stylesheets/poll.css.scss b/app/assets/stylesheets/poll.css.scss index f72039acb..dd5c89f4f 100644 --- a/app/assets/stylesheets/poll.css.scss +++ b/app/assets/stylesheets/poll.css.scss @@ -20,7 +20,7 @@ position:absolute; width:0px; height:15px; - top:-10px; + top:-12px; z-index:-1; background-color:$background-grey; } diff --git a/app/assets/templates/poll_tpl.jst.hbs b/app/assets/templates/poll_tpl.jst.hbs index 0d10be448..ed9e18e7c 100644 --- a/app/assets/templates/poll_tpl.jst.hbs +++ b/app/assets/templates/poll_tpl.jst.hbs @@ -1,32 +1,32 @@ {{#if poll}}
-

{{t "poll.count" votes=poll.participation_count}}

+

{{t "poll.count" count=poll.participation_count}}

{{poll.question}}
{{#unless already_participated_in_poll}}
{{#poll.poll_answers}} - - {{answer}} + + + {{answer}} +
{{/poll.poll_answers}}

-
{{t "poll.toggle_result"}}
+
{{t "poll.show_result"}}

- {{/unless}} -
-
{{t "poll.result"}}
+ {{else}} {{#poll.poll_answers}} -
-
-
-
- {{answer}} -

+
+
+ {{answer}} +

+
{{/poll.poll_answers}} -
- + {{/unless}}
{{/if}} \ No newline at end of file diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index 4f6f09424..dd00036a2 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -176,5 +176,8 @@ en: poll: vote: "Vote" result: "Result" - count: "<%=votes%> votes so far" - toggle_result: "Toggle result" \ No newline at end of file + count: + one: "1 vote so far" + other: "<%=count%> votes so far" + show_result: "Show result" + close_result: "Close result" \ No newline at end of file From 7dcf11e62923456a63a1128e73b3c92f8171a242 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Thu, 27 Mar 2014 01:50:02 +0100 Subject: [PATCH 14/23] fixed federation bug due to roxml missing underscore --- app/models/poll_participation.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/poll_participation.rb b/app/models/poll_participation.rb index 3e1f7c368..5a5c472dd 100644 --- a/app/models/poll_participation.rb +++ b/app/models/poll_participation.rb @@ -9,6 +9,7 @@ class PollParticipation < ActiveRecord::Base belongs_to :author, :class_name => 'Person', :foreign_key => :author_id xml_attr :diaspora_handle xml_attr :poll_answer_guid + xml_convention :underscore validate :not_already_participated after_commit :update_vote_counter, :on => :create From 8f9736a7413ad0b0d0babcf520831caf861d824a Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Thu, 27 Mar 2014 09:46:32 +0100 Subject: [PATCH 15/23] fixed poll js bug --- app/assets/javascripts/app/views/poll.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/app/views/poll.js b/app/assets/javascripts/app/views/poll.js index b16fd8706..cc0ca18d3 100644 --- a/app/assets/javascripts/app/views/poll.js +++ b/app/assets/javascripts/app/views/poll.js @@ -48,9 +48,8 @@ app.views.Poll = app.views.Base.extend({ this.toggleMode = 1; }else{ this.$('.toggle_result').html(Diaspora.I18n.t("poll.show_result")); - this.toggleStringMode = 0; + this.toggleMode = 0; } - return false; }, From a9843ae9968aab890090de9238ca41d0cee9d088 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Thu, 27 Mar 2014 21:44:35 +0100 Subject: [PATCH 16/23] added cucumber tests, updated spec with xml class test --- .gitignore | 3 + app/models/poll_answer.rb | 2 +- features/desktop/post_with_a_poll.feature | 65 +++++++++++++++++++ .../step_definitions/post_with_poll_steps.rb | 32 +++++++++ spec/models/poll_participation_spec.rb | 4 ++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 features/desktop/post_with_a_poll.feature create mode 100644 features/step_definitions/post_with_poll_steps.rb diff --git a/.gitignore b/.gitignore index c1f6c385d..7d4f3c5ef 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,6 @@ dump.rdb #Rubinius's JIT *.rbc + +#IDE +diaspora.iml diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb index 8c8de154b..1fa9b8eeb 100644 --- a/app/models/poll_answer.rb +++ b/app/models/poll_answer.rb @@ -11,7 +11,7 @@ class PollAnswer < ActiveRecord::Base self.include_root_in_json = false def update_vote_counter - self.vote_count = self.vote_count + 1 + self.vote_count += 1 self.save! end diff --git a/features/desktop/post_with_a_poll.feature b/features/desktop/post_with_a_poll.feature new file mode 100644 index 000000000..5d8b7b277 --- /dev/null +++ b/features/desktop/post_with_a_poll.feature @@ -0,0 +1,65 @@ +@javascript +Feature: posting with a poll + + Background: + Given following users exist: + | username | + | bob | + And I sign in as "bob@bob.bob" + And I am on the home page + + Scenario: expanding the publisher + Given "#poll_creator_wrapper" is hidden + When I expand the publisher + Then I should see an element "#poll_creator" + + Scenario: expanding the poll creator + Given "#poll_creator_wrapper" is hidden + When I expand the publisher + And I press the element "#poll_creator" + Then I should see an element "#poll_creator_wrapper" + + Scenario: adding option to poll + Given "#poll_creator_wrapper" is hidden + When I expand the publisher + And I press the element "#poll_creator" + And I press the element "#add_poll_answer" + Then I should see 3 options + + Scenario: delete an option + Given "#poll_creator_wrapper" is hidden + When I expand the publisher + And I press the element "#poll_creator" + And I delete the first option + Then I should see 1 option + And I should not see a remove icon + + Scenario: post with an attached poll + Given I expand the publisher + And I press the element "#poll_creator" + When I fill in the following: + | status_message_fake_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | + And I fill in the following for the options: + | normal | + | not normal | + And I press "Share" + Then I should see a ".poll_form" within ".stream_element" + And I should see a "form" within ".stream_element" + + Scenario: vote for an option + Given I expand the publisher + And I press the element "#poll_creator" + When I fill in the following: + | status_message_fake_text | I am eating yogurt | + | poll_question | What kind of yogurt do you like? | + And I fill in the following for the options: + | normal | + | not normal | + And I press "Share" + + And I check the first option + And I press "Vote" within ".stream_element" + Then I should see an element ".poll_progress_bar" + And I should see an element ".percentage" + And I should see "1 vote so far" within ".poll_statistic" \ No newline at end of file diff --git a/features/step_definitions/post_with_poll_steps.rb b/features/step_definitions/post_with_poll_steps.rb new file mode 100644 index 000000000..2ae5a78ba --- /dev/null +++ b/features/step_definitions/post_with_poll_steps.rb @@ -0,0 +1,32 @@ +Then /^I should see ([1-9]+) options?$/ do |number| + find("#poll_creator_wrapper").all(".poll_answer").count.should eql(number.to_i) +end + +And /^I delete the first option$/ do + find("#poll_creator_wrapper").all(".poll_answer .remove_poll_answer").first.click +end + +And /^I should not see a remove icon$/ do + page.should_not have_css(".remove_poll_answer") +end + +When /^I fill in the following for the options:$/ do |table| + i = 0 + table.raw.flatten.each do |value| + all(".poll_answer_input")[i].set(value) + i+=1 + end +end + +When /^I check the first option$/ do + sleep 1 + first(".poll_form input").click +end + +And /^I press the element "([^"]*)"$/ do |selector| + find(selector).click +end + +Then /^I should see an element "([^"]*)"$/ do |selector| + page.should have_css(selector) +end \ No newline at end of file diff --git a/spec/models/poll_participation_spec.rb b/spec/models/poll_participation_spec.rb index 951d14144..13a9e0f63 100644 --- a/spec/models/poll_participation_spec.rb +++ b/spec/models/poll_participation_spec.rb @@ -43,6 +43,10 @@ describe PollParticipation do @xml = @poll_participation.to_xml.to_s end + it 'serializes the class name' do + @xml.include?(PollParticipation.name.underscore.to_s).should be_true + end + it 'serializes the sender handle' do @xml.include?(@poll_participation.diaspora_handle).should be_true end From dde39aa1bb019ed88b0315adb9d6464234d2acba Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Thu, 27 Mar 2014 23:34:33 +0100 Subject: [PATCH 17/23] added jasmine publisher tests --- spec/javascripts/app/views/poll_view_spec.js | 3 ++ .../app/views/publisher_view_spec.js | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 spec/javascripts/app/views/poll_view_spec.js diff --git a/spec/javascripts/app/views/poll_view_spec.js b/spec/javascripts/app/views/poll_view_spec.js new file mode 100644 index 000000000..40cf182dd --- /dev/null +++ b/spec/javascripts/app/views/poll_view_spec.js @@ -0,0 +1,3 @@ +describe("app.views.Poll", function(){ + +}); diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index fb753f01f..4d7a809ad 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -277,6 +277,40 @@ describe("app.views.Publisher", function() { }); + context("poll", function(){ + beforeEach(function() { + loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); + spec.loadFixture("aspects_index"); + $("#poll_creator_wrapper").hide(); //css not loaded? :-/ + this.view = new app.views.Publisher(); + }); + + describe('#showPollCreator', function(){ + it("Shows the poll creator", function(){ + expect($("#poll_creator_wrapper").is(":visible")).toBe(false); + this.view.showPollCreator(); + expect($("#poll_creator_wrapper").is(":visible")).toBe(true); + }) + }); + + describe("#addPollAnswer", function(){ + it("should add a poll answer if clicked", function(){ + expect($("#poll_creator_wrapper .poll_answer").length).toBe(2); + this.view.addPollAnswer(); + expect($("#poll_creator_wrapper .poll_answer").length).toBe(3); + }) + }); + + describe("#removePollAnswer", function(){ + it("should remove a poll answer if clicked", function(){ + var answer_count = $('.poll_answer').length; + var evt = {'currentTarget' : $("#poll_creator_wrapper .poll_answer:first .remove_poll_answer")}; + this.view.removePollAnswer(evt); + expect($("#poll_creator_wrapper .poll_answer").length).toBe(answer_count-1); + }) + }); + }); + context("locator", function() { beforeEach(function() { // should be jasmine helper From 2d0abbae23d7a3725578b862bb98b44d9e395ef3 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Fri, 28 Mar 2014 13:53:36 +0100 Subject: [PATCH 18/23] added jasmine test for poll view --- .../app/views/{poll.js => poll_view.js} | 2 +- spec/javascripts/app/views/poll_view_spec.js | 42 +++++++++++++++++++ spec/javascripts/helpers/factory.js | 20 +++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) rename app/assets/javascripts/app/views/{poll.js => poll_view.js} (98%) diff --git a/app/assets/javascripts/app/views/poll.js b/app/assets/javascripts/app/views/poll_view.js similarity index 98% rename from app/assets/javascripts/app/views/poll.js rename to app/assets/javascripts/app/views/poll_view.js index cc0ca18d3..ed8a09fb5 100644 --- a/app/assets/javascripts/app/views/poll.js +++ b/app/assets/javascripts/app/views/poll_view.js @@ -76,7 +76,7 @@ app.views.Poll = app.views.Base.extend({ var parent = this; pollParticipation.save({ "poll_answer_id" : result, - "poll_id" : this.poll.poll_id, + "poll_id" : this.poll.poll_id },{ url : "/posts/"+this.poll.post_id+"/poll_participations", success : function(model, response) { diff --git a/spec/javascripts/app/views/poll_view_spec.js b/spec/javascripts/app/views/poll_view_spec.js index 40cf182dd..4ee1a2ef8 100644 --- a/spec/javascripts/app/views/poll_view_spec.js +++ b/spec/javascripts/app/views/poll_view_spec.js @@ -1,3 +1,45 @@ describe("app.views.Poll", function(){ + beforeEach(function() { + loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); + this.view = new app.views.Poll({ "model" : factory.postWithPoll()}); + this.view.render(); + }); + describe("setProgressBar", function(){ + it("sets the progress bar according to the voting result", function(){ + var percentage = (this.view.poll.poll_answers[0].vote_count / this.view.poll.participation_count)*100; + expect(this.view.$('.poll_progress_bar:first').css('width')).toBe(this.view.progressBarFactor * percentage+"px"); + expect(this.view.$(".percentage:first").text()).toBe(" - " + percentage + "%"); + }) + }); + + describe("toggleResult", function(){ + it("toggles the progress bar and result", function(){ + expect(this.view.$('.poll_progress_bar_wrapper:first').css('display')).toBe("none"); + this.view.toggleResult(null); + expect(this.view.$('.poll_progress_bar_wrapper:first').css('display')).toBe("block"); + }) + }); + + describe("updateCounter", function(){ + it("updates the counter after a vote", function(){ + var pc = this.view.poll.participation_count; + var answerCount = this.view.poll.poll_answers[0].vote_count; + this.view.updateCounter(1); + expect(this.view.poll.participation_count).toBe(pc+1); + expect(this.view.poll.poll_answers[0].vote_count).toBe(answerCount+1); + }) + }); + + describe("vote", function(){ + it("checks the ajax call for voting", function(){ + spyOn($, "ajax"); + var radio = this.view.$('input[name="vote"]:first'); + radio.attr('checked', true); + this.view.vote({'target' : radio}); + var obj = JSON.parse($.ajax.mostRecentCall.args[0].data); + expect(obj.poll_id).toBe(this.view.poll.poll_id); + expect(obj.poll_answer_id).toBe(this.view.poll.poll_answers[0].id); + }) + }) }); diff --git a/spec/javascripts/helpers/factory.js b/spec/javascripts/helpers/factory.js index a3c8692ac..b5dd63068 100644 --- a/spec/javascripts/helpers/factory.js +++ b/spec/javascripts/helpers/factory.js @@ -124,11 +124,31 @@ factory = { return new app.models.Post(_.extend(defaultAttrs, overrides)) }, + postWithPoll : function(overrides) { + defaultAttrs = _.extend(factory.postAttrs(), {"author" : this.author()}); + defaultAttrs = _.extend(defaultAttrs, {"already_participated_in_poll" : false}); + defaultAttrs = _.extend(defaultAttrs, {"poll" : factory.poll()}); + return new app.models.Post(_.extend(defaultAttrs, overrides)); + }, + statusMessage : function(overrides){ //intentionally doesn't have an author to mirror creation process, maybe we should change the creation process return new app.models.StatusMessage(_.extend(factory.postAttrs(), overrides)) }, + poll: function(overrides){ + return { + "question" : "This is an awesome question", + "created_at" : "2012-01-03T19:53:13Z", + "author" : this.author(), + "post_id" : 1, + "poll_answers" : [{"answer" : "yes", "id" : 1, "vote_count" : 9}, {"answer" : "no", "id" : 2, "vote_count" : 1}], + "guid" : this.guid(), + "poll_id": this.id.next(), + "participation_count" : 10 + } + }, + comment: function(overrides) { var defaultAttrs = { "text" : "This is an awesome comment!", From a3837a4f190be833397605e86e20efa8ae8dc7da Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Fri, 28 Mar 2014 13:57:08 +0100 Subject: [PATCH 19/23] added changelog entry --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index e9111f660..2187d8c15 100644 --- a/Changelog.md +++ b/Changelog.md @@ -40,6 +40,7 @@ * Added comment count to statistic to enable calculations of posts/comments ratios [#4799](https://github.com/diaspora/diaspora/pull/4799) * Add filters to notifications controller [#4814](https://github.com/diaspora/diaspora/pull/4814) * Activate hovercards in SPV and conversations [#4870](https://github.com/diaspora/diaspora/pull/4870) +* Added possibility to conduct polls # 0.3.0.3 @@ -58,6 +59,7 @@ ## Bug fixes * Fix regression caused by using after_commit with nested '#save' which lead to an infinite recursion [#4715](https://github.com/diaspora/diaspora/issues/4715) * Save textarea value before rendering comments when clicked 'show more...' [#4514](https://github.com/diaspora/diaspora/issues/4514) + # 0.3.0.0 ## Pod statistics From 167884e5653adafb8964b2981c1b82f117a51d87 Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Fri, 28 Mar 2014 16:29:08 +0100 Subject: [PATCH 20/23] added changelog pull link --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 2187d8c15..6aa69902f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -40,7 +40,7 @@ * Added comment count to statistic to enable calculations of posts/comments ratios [#4799](https://github.com/diaspora/diaspora/pull/4799) * Add filters to notifications controller [#4814](https://github.com/diaspora/diaspora/pull/4814) * Activate hovercards in SPV and conversations [#4870](https://github.com/diaspora/diaspora/pull/4870) -* Added possibility to conduct polls +* Added possibility to conduct polls [#4861](https://github.com/diaspora/diaspora/pull/4861) # 0.3.0.3 From 4174b88987b8b5c4a7420020794a05af2569acca Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Sat, 29 Mar 2014 10:55:20 +0100 Subject: [PATCH 21/23] percentage result round + minor language fix --- app/assets/javascripts/app/views/poll_view.js | 2 +- config/locales/javascript/javascript.en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/app/views/poll_view.js b/app/assets/javascripts/app/views/poll_view.js index ed8a09fb5..9a1df2a88 100644 --- a/app/assets/javascripts/app/views/poll_view.js +++ b/app/assets/javascripts/app/views/poll_view.js @@ -31,7 +31,7 @@ app.views.Poll = app.views.Base.extend({ for(index = 0; index < answers.length; ++index) { var percentage = 0; if(this.poll.participation_count != 0) { - percentage = answers[index].vote_count / this.poll.participation_count * 100; + percentage = Math.round(answers[index].vote_count / this.poll.participation_count * 100); } var progressBar = this.$(".poll_progress_bar[data-answerid="+answers[index].id+"]"); progressBar.parent().next().html(" - " + percentage + "%"); diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index dd00036a2..91527ffc1 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -180,4 +180,4 @@ en: one: "1 vote so far" other: "<%=count%> votes so far" show_result: "Show result" - close_result: "Close result" \ No newline at end of file + close_result: "Hide result" \ No newline at end of file From 6f3844b73bb954e5e1bbf8d18c9dfbc31a02810f Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Sun, 30 Mar 2014 16:48:15 +0200 Subject: [PATCH 22/23] fixed language files, added rails cache counter for poll answer, fixed bug with same poll input for form --- app/assets/javascripts/app/views/publisher_view.js | 8 ++++++++ app/models/poll_answer.rb | 5 ----- app/models/poll_participation.rb | 8 +------- config/locales/diaspora/en-AU.yml | 8 ++++++++ config/locales/diaspora/en-GB.yml | 8 ++++++++ config/locales/diaspora/en-US.yml | 9 ++++++++- 6 files changed, 33 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index b2c58e4c7..295281bcc 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -333,6 +333,9 @@ app.views.Publisher = Backbone.View.extend({ // clear location this.destroyLocation(); + // clear poll form + this.clearPollForm(); + // force textchange plugin to update lastValue this.el_input.data('lastValue', ''); this.el_hiddenInput.data('lastValue', ''); @@ -340,6 +343,11 @@ app.views.Publisher = Backbone.View.extend({ return this; }, + clearPollForm : function(){ + this.$('#poll_question').val(''); + this.$('.poll_answer_input').val(''); + }, + tryClose : function(){ // if it is not submittable, close it. if( !this._submittable() ){ diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb index 1fa9b8eeb..e3cc13269 100644 --- a/app/models/poll_answer.rb +++ b/app/models/poll_answer.rb @@ -10,9 +10,4 @@ class PollAnswer < ActiveRecord::Base self.include_root_in_json = false - def update_vote_counter - self.vote_count += 1 - self.save! - end - end diff --git a/app/models/poll_participation.rb b/app/models/poll_participation.rb index 5a5c472dd..590a62830 100644 --- a/app/models/poll_participation.rb +++ b/app/models/poll_participation.rb @@ -5,19 +5,13 @@ class PollParticipation < ActiveRecord::Base include Diaspora::Guid include Diaspora::Relayable belongs_to :poll - belongs_to :poll_answer + belongs_to :poll_answer, counter_cache: :vote_count belongs_to :author, :class_name => 'Person', :foreign_key => :author_id xml_attr :diaspora_handle xml_attr :poll_answer_guid xml_convention :underscore validate :not_already_participated - after_commit :update_vote_counter, :on => :create - - def update_vote_counter - self.poll_answer.update_vote_counter - end - def parent_class Poll end diff --git a/config/locales/diaspora/en-AU.yml b/config/locales/diaspora/en-AU.yml index 7713db61b..f34d29a1f 100644 --- a/config/locales/diaspora/en-AU.yml +++ b/config/locales/diaspora/en-AU.yml @@ -26,3 +26,11 @@ attributes: from_id: taken: "is a duplicate of a pre-existing request." + poll: + attributes: + poll_answers: + not_enough_poll_answers: "Not enough poll options provided." + poll_participation: + attributes: + poll: + already_participated: "You've already participated in this poll!" diff --git a/config/locales/diaspora/en-GB.yml b/config/locales/diaspora/en-GB.yml index afd094c31..d6ae6e10e 100644 --- a/config/locales/diaspora/en-GB.yml +++ b/config/locales/diaspora/en-GB.yml @@ -26,3 +26,11 @@ attributes: from_id: taken: "is a duplicate of a pre-existing request." + poll: + attributes: + poll_answers: + not_enough_poll_answers: "Not enough poll options provided." + poll_participation: + attributes: + poll: + already_participated: "You've already participated in this poll!" diff --git a/config/locales/diaspora/en-US.yml b/config/locales/diaspora/en-US.yml index e2a634aa0..c527a04bb 100644 --- a/config/locales/diaspora/en-US.yml +++ b/config/locales/diaspora/en-US.yml @@ -26,4 +26,11 @@ attributes: from_id: taken: "is a duplicate of a pre-existing request." - + poll: + attributes: + poll_answers: + not_enough_poll_answers: "Not enough poll options provided." + poll_participation: + attributes: + poll: + already_participated: "You've already participated in this poll!" From 4130592ca5d131505b246eacb6701c425c3df40e Mon Sep 17 00:00:00 2001 From: Jannik Streek Date: Mon, 31 Mar 2014 18:30:01 +0200 Subject: [PATCH 23/23] fixed bookmarklet --- app/assets/stylesheets/publisher.css.scss | 3 +++ app/assets/stylesheets/publisher_blueprint.css.scss | 2 +- app/views/publisher/_publisher_blueprint.html.haml | 2 -- app/views/publisher/_publisher_bootstrap.html.haml | 3 +-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/publisher.css.scss b/app/assets/stylesheets/publisher.css.scss index bdb835dca..550221777 100644 --- a/app/assets/stylesheets/publisher.css.scss +++ b/app/assets/stylesheets/publisher.css.scss @@ -87,6 +87,9 @@ display:none; border-top: 1px dashed $border-grey; padding:4px 6px 4px 6px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } &.with_location .row-fluid#location_container { diff --git a/app/assets/stylesheets/publisher_blueprint.css.scss b/app/assets/stylesheets/publisher_blueprint.css.scss index d252f0578..9865e7997 100644 --- a/app/assets/stylesheets/publisher_blueprint.css.scss +++ b/app/assets/stylesheets/publisher_blueprint.css.scss @@ -338,6 +338,7 @@ display:none; border: 1px solid $border-dark-grey; padding:5px; + margin-top:1em; @include border-radius(2px); } @@ -363,7 +364,6 @@ } #poll_question_wrapper { - margin-right:24px; } #poll_question { diff --git a/app/views/publisher/_publisher_blueprint.html.haml b/app/views/publisher/_publisher_blueprint.html.haml index cccf338d6..75918f3fe 100644 --- a/app/views/publisher/_publisher_blueprint.html.haml +++ b/app/views/publisher/_publisher_blueprint.html.haml @@ -37,9 +37,7 @@ = image_tag 'icons/camera.png', :alt => t('shared.publisher.upload_photos').titleize, :class => 'publisher_image' = hidden_field :location, :coords #location_container - %br #poll_creator_wrapper - = t('shared.publisher.poll.add_a_poll') #poll_question_wrapper %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question'} .poll_answer diff --git a/app/views/publisher/_publisher_bootstrap.html.haml b/app/views/publisher/_publisher_bootstrap.html.haml index 103c53d5a..a35f22d36 100644 --- a/app/views/publisher/_publisher_bootstrap.html.haml +++ b/app/views/publisher/_publisher_bootstrap.html.haml @@ -22,8 +22,7 @@ %ul#photodropzone .row-fluid#location_container = hidden_field :location, :coords - .row-fluid#poll_creator_wrapper - = t('shared.publisher.poll.add_a_poll') + .row-fluid#poll_creator_wrapper #poll_question_wrapper{:class => "input-block-level"} %input{:id => 'poll_question', :placeholder => t('shared.publisher.poll.question'), :name => 'poll_question', :class=> "form-control"} .poll_answer