mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 03:54:59 +08:00
commit
634b769cda
|
@ -425,7 +425,8 @@ Discourse.Composer = Discourse.Model.extend({
|
||||||
this.set('composeState', CLOSED);
|
this.set('composeState', CLOSED);
|
||||||
|
|
||||||
return Ember.Deferred.promise(function(promise) {
|
return Ember.Deferred.promise(function(promise) {
|
||||||
post.save(function() {
|
post.save(function(result) {
|
||||||
|
post.updateFromPost(result);
|
||||||
composer.clearState();
|
composer.clearState();
|
||||||
}, function(error) {
|
}, function(error) {
|
||||||
var response = $.parseJSON(error.responseText);
|
var response = $.parseJSON(error.responseText);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<table>
|
||||||
|
{{#each poll.options}}
|
||||||
|
<tr {{bind-attr class=checked:active}} {{action selectOption option}}>
|
||||||
|
<td class="radio"><input type="radio" name="poll" {{bind-attr checked=checked disabled=controller.loading}}></td>
|
||||||
|
<td class="option">
|
||||||
|
<div class="option">
|
||||||
|
{{option}}
|
||||||
|
</div>
|
||||||
|
{{#if controller.showResults}}
|
||||||
|
<div class="result">{{i18n poll.voteCount count=votes}}</div>
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button {{action toggleShowResults}}>
|
||||||
|
{{#if showResults}}
|
||||||
|
{{i18n poll.results.hide}}
|
||||||
|
{{else}}
|
||||||
|
{{i18n poll.results.show}}
|
||||||
|
{{/if}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{{#if loading}}
|
||||||
|
<i class="fa fa-spin fa-spinner"></i>
|
||||||
|
{{/if}}
|
9
plugins/poll/assets/javascripts/poll_bbcode.js
Normal file
9
plugins/poll/assets/javascripts/poll_bbcode.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Discourse.Dialect.inlineBetween({
|
||||||
|
start: '[poll]',
|
||||||
|
stop: '[/poll]',
|
||||||
|
rawContents: true,
|
||||||
|
emitter: function(contents) {
|
||||||
|
var list = Discourse.Dialect.cook(contents, {});
|
||||||
|
return ['div', {class: 'poll-ui'}, list];
|
||||||
|
}
|
||||||
|
});
|
110
plugins/poll/assets/javascripts/poll_ui.js
Normal file
110
plugins/poll/assets/javascripts/poll_ui.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
var Poll = Discourse.Model.extend({
|
||||||
|
post: null,
|
||||||
|
options: [],
|
||||||
|
|
||||||
|
postObserver: function() {
|
||||||
|
this.updateOptionsFromJson(this.get('post.poll_details'));
|
||||||
|
}.observes('post.poll_details'),
|
||||||
|
|
||||||
|
updateOptionsFromJson: function(json) {
|
||||||
|
var selectedOption = json["selected"];
|
||||||
|
|
||||||
|
var options = [];
|
||||||
|
Object.keys(json["options"]).forEach(function(option) {
|
||||||
|
options.push(Ember.Object.create({
|
||||||
|
option: option,
|
||||||
|
votes: json["options"][option],
|
||||||
|
checked: (option == selectedOption)
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
this.set('options', options);
|
||||||
|
},
|
||||||
|
|
||||||
|
saveVote: function(option) {
|
||||||
|
this.get('options').forEach(function(opt) {
|
||||||
|
opt.set('checked', opt.get('option') == option);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Discourse.ajax("/poll", {
|
||||||
|
type: "PUT",
|
||||||
|
data: {post_id: this.get('post.id'), option: option}
|
||||||
|
}).then(function(newJSON) {
|
||||||
|
this.updateOptionsFromJson(newJSON);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var PollController = Discourse.Controller.extend({
|
||||||
|
poll: null,
|
||||||
|
showResults: false,
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
selectOption: function(option) {
|
||||||
|
if (!this.get('currentUser.id')) {
|
||||||
|
this.get('postController').send('showLogin');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set('loading', true);
|
||||||
|
this.get('poll').saveVote(option).then(function() {
|
||||||
|
this.set('loading', false);
|
||||||
|
this.set('showResults', true);
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleShowResults: function() {
|
||||||
|
this.set('showResults', !this.get('showResults'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var PollView = Ember.View.extend({
|
||||||
|
templateName: "poll",
|
||||||
|
classNames: ['poll-ui'],
|
||||||
|
|
||||||
|
replaceElement: function(target) {
|
||||||
|
this._insertElementLater(function() {
|
||||||
|
target.replaceWith(this.$());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function initializePollView(self) {
|
||||||
|
var post = self.get('post');
|
||||||
|
var pollDetails = post.get('poll_details');
|
||||||
|
|
||||||
|
var poll = Poll.create({post: post});
|
||||||
|
poll.updateOptionsFromJson(pollDetails);
|
||||||
|
|
||||||
|
var pollController = PollController.create({
|
||||||
|
poll: poll,
|
||||||
|
showResults: pollDetails["selected"],
|
||||||
|
postController: self.get('controller')
|
||||||
|
});
|
||||||
|
|
||||||
|
var pollView = self.createChildView(PollView, {
|
||||||
|
controller: pollController
|
||||||
|
});
|
||||||
|
return pollView;
|
||||||
|
}
|
||||||
|
|
||||||
|
Discourse.PostView.reopen({
|
||||||
|
createPollUI: function($post) {
|
||||||
|
var post = this.get('post');
|
||||||
|
|
||||||
|
if (!post.get('poll_details')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = initializePollView(this);
|
||||||
|
view.replaceElement($post.find(".poll-ui:first"));
|
||||||
|
this.set('pollView', view);
|
||||||
|
|
||||||
|
}.on('postViewInserted'),
|
||||||
|
|
||||||
|
clearPollView: function() {
|
||||||
|
if (this.get('pollView')) {
|
||||||
|
this.get('pollView').destroy();
|
||||||
|
}
|
||||||
|
}.on('willClearRender')
|
||||||
|
});
|
17
plugins/poll/config/locales/client.en.yml
Normal file
17
plugins/poll/config/locales/client.en.yml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
# This file contains content for the client portion of Discourse, sent out
|
||||||
|
# to the Javascript app.
|
||||||
|
#
|
||||||
|
# To validate this YAML file after you change it, please paste it into
|
||||||
|
# http://yamllint.com/
|
||||||
|
|
||||||
|
en:
|
||||||
|
js:
|
||||||
|
poll:
|
||||||
|
voteCount:
|
||||||
|
one: "1 vote"
|
||||||
|
other: "%{count} votes"
|
||||||
|
|
||||||
|
results:
|
||||||
|
show: Show Results
|
||||||
|
hide: Hide Results
|
11
plugins/poll/config/locales/server.en.yml
Normal file
11
plugins/poll/config/locales/server.en.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
# This file contains content for the server portion of Discourse used by Ruby
|
||||||
|
#
|
||||||
|
# To validate this YAML file after you change it, please paste it into
|
||||||
|
# http://yamllint.com/
|
||||||
|
|
||||||
|
en:
|
||||||
|
poll:
|
||||||
|
must_contain_poll_options: "must contain a list of poll options"
|
||||||
|
cannot_have_modified_options: "cannot have modified poll options after 5 minutes"
|
||||||
|
prefix: "Poll:"
|
159
plugins/poll/plugin.rb
Normal file
159
plugins/poll/plugin.rb
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
# name: poll
|
||||||
|
# about: adds poll support to Discourse
|
||||||
|
# version: 0.1
|
||||||
|
# authors: Vikhyat Korrapati
|
||||||
|
|
||||||
|
load File.expand_path("../poll.rb", __FILE__)
|
||||||
|
|
||||||
|
# Without this line we can't lookup the constant inside the after_initialize blocks,
|
||||||
|
# probably because all of this is instance_eval'd inside an instance of
|
||||||
|
# Plugin::Instance.
|
||||||
|
PollPlugin = PollPlugin
|
||||||
|
|
||||||
|
after_initialize do
|
||||||
|
# Rails Engine for accepting votes.
|
||||||
|
module PollPlugin
|
||||||
|
class Engine < ::Rails::Engine
|
||||||
|
engine_name "poll_plugin"
|
||||||
|
isolate_namespace PollPlugin
|
||||||
|
end
|
||||||
|
|
||||||
|
class PollController < ActionController::Base
|
||||||
|
include CurrentUser
|
||||||
|
|
||||||
|
def vote
|
||||||
|
if current_user.nil?
|
||||||
|
render status: :forbidden, json: false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:post_id].nil? or params[:option].nil?
|
||||||
|
render status: 400, json: false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
post = Post.find(params[:post_id])
|
||||||
|
poll = PollPlugin::Poll.new(post)
|
||||||
|
unless poll.is_poll?
|
||||||
|
render status: 400, json: false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
options = poll.details
|
||||||
|
|
||||||
|
unless options.keys.include? params[:option]
|
||||||
|
render status: 400, json: false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
poll.set_vote!(current_user, params[:option])
|
||||||
|
|
||||||
|
render json: poll.serialize(current_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
PollPlugin::Engine.routes.draw do
|
||||||
|
put '/' => 'poll#vote'
|
||||||
|
end
|
||||||
|
|
||||||
|
Discourse::Application.routes.append do
|
||||||
|
mount ::PollPlugin::Engine, at: '/poll'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Starting a topic title with "Poll:" will create a poll topic. If the title
|
||||||
|
# starts with "poll:" but the first post doesn't contain a list of options in
|
||||||
|
# it we need to raise an error.
|
||||||
|
# Need to add an error when:
|
||||||
|
# * there is no list of options.
|
||||||
|
Post.class_eval do
|
||||||
|
validate :poll_options
|
||||||
|
def poll_options
|
||||||
|
poll = PollPlugin::Poll.new(self)
|
||||||
|
|
||||||
|
return unless poll.is_poll?
|
||||||
|
|
||||||
|
if poll.options.length == 0
|
||||||
|
self.errors.add(:raw, I18n.t('poll.must_contain_poll_options'))
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.created_at and self.created_at < 5.minutes.ago and poll.options.sort != poll.details.keys.sort
|
||||||
|
self.errors.add(:raw, I18n.t('poll.cannot_have_modified_options'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Save the list of options to PluginStore after the post is saved.
|
||||||
|
Post.class_eval do
|
||||||
|
after_save :save_poll_options_to_topic_metadata
|
||||||
|
def save_poll_options_to_topic_metadata
|
||||||
|
poll = PollPlugin::Poll.new(self)
|
||||||
|
if poll.is_poll?
|
||||||
|
details = poll.details || {}
|
||||||
|
new_options = poll.options
|
||||||
|
details.each do |key, value|
|
||||||
|
unless new_options.include? key
|
||||||
|
details.delete(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
new_options.each do |key|
|
||||||
|
details[key] ||= 0
|
||||||
|
end
|
||||||
|
poll.set_details! details
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add poll details into the post serializer.
|
||||||
|
PostSerializer.class_eval do
|
||||||
|
attributes :poll_details
|
||||||
|
def poll_details
|
||||||
|
PollPlugin::Poll.new(object).serialize(scope.user)
|
||||||
|
end
|
||||||
|
def include_poll_details?
|
||||||
|
PollPlugin::Poll.new(object).is_poll?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Poll UI.
|
||||||
|
register_asset "javascripts/discourse/templates/poll.js.handlebars"
|
||||||
|
register_asset "javascripts/poll_ui.js"
|
||||||
|
register_asset "javascripts/poll_bbcode.js", :server_side
|
||||||
|
|
||||||
|
register_css <<CSS
|
||||||
|
|
||||||
|
.poll-ui table {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui tr {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui td.radio input {
|
||||||
|
margin-left: -10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui td {
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui td.option .option {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui td.option .result {
|
||||||
|
float: right;
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui tr.active {
|
||||||
|
background-color: #FFFFB3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-ui button {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSS
|
77
plugins/poll/poll.rb
Normal file
77
plugins/poll/poll.rb
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
module ::PollPlugin
|
||||||
|
|
||||||
|
class Poll
|
||||||
|
def initialize(post)
|
||||||
|
@post = post
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_poll?
|
||||||
|
if !@post.post_number.nil? and @post.post_number > 1
|
||||||
|
# Not a new post, and also not the first post.
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
topic = @post.topic
|
||||||
|
|
||||||
|
# Topic is not set in a couple of cases in the Discourse test suite.
|
||||||
|
return false if topic.nil?
|
||||||
|
|
||||||
|
if @post.post_number.nil? and topic.highest_post_number > 0
|
||||||
|
# New post, but not the first post in the topic.
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
topic.title =~ /^#{I18n.t('poll.prefix')}/i
|
||||||
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
cooked = PrettyText.cook(@post.raw, topic_id: @post.topic_id)
|
||||||
|
poll_div = Nokogiri::HTML(cooked).css(".poll-ui").first
|
||||||
|
if poll_div
|
||||||
|
poll_div.css("li").map {|x| x.children.to_s.strip }.uniq
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def details
|
||||||
|
@details ||= ::PluginStore.get("poll", details_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_details!(new_details)
|
||||||
|
::PluginStore.set("poll", details_key, new_details)
|
||||||
|
@details = new_details
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_vote(user)
|
||||||
|
user.nil? ? nil : ::PluginStore.get("poll", vote_key(user))
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_vote!(user, option)
|
||||||
|
# Get the user's current vote.
|
||||||
|
vote = get_vote(user)
|
||||||
|
vote = nil unless details.keys.include? vote
|
||||||
|
|
||||||
|
new_details = details.dup
|
||||||
|
new_details[vote] -= 1 if vote
|
||||||
|
new_details[option] += 1
|
||||||
|
|
||||||
|
::PluginStore.set("poll", vote_key(user), option)
|
||||||
|
set_details! new_details
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize(user)
|
||||||
|
return nil if details.nil?
|
||||||
|
{options: details, selected: get_vote(user)}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def details_key
|
||||||
|
"poll_options_#{@post.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def vote_key(user)
|
||||||
|
"poll_vote_#{@post.id}_#{user.id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
51
plugins/poll/spec/poll_plugin/poll_controller_spec.rb
Normal file
51
plugins/poll/spec/poll_plugin/poll_controller_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe PollPlugin::PollController, type: :controller do
|
||||||
|
let(:topic) { create_topic(title: "Poll: Chitoge vs Onodera") }
|
||||||
|
let(:post) { create_post(topic: topic, raw: "Pick one.\n\n[poll]\n* Chitoge\n* Onodera\n[/poll]") }
|
||||||
|
let(:user1) { Fabricate(:user) }
|
||||||
|
let(:user2) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it "should return 403 if no user is logged in" do
|
||||||
|
xhr :put, :vote, post_id: post.id, option: "Chitoge", use_route: :poll
|
||||||
|
response.should be_forbidden
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return 400 if post_id or invalid option is not specified" do
|
||||||
|
log_in_user user1
|
||||||
|
xhr :put, :vote, use_route: :poll
|
||||||
|
response.status.should eq(400)
|
||||||
|
xhr :put, :vote, post_id: post.id, use_route: :poll
|
||||||
|
response.status.should eq(400)
|
||||||
|
xhr :put, :vote, option: "Chitoge", use_route: :poll
|
||||||
|
response.status.should eq(400)
|
||||||
|
xhr :put, :vote, post_id: post.id, option: "Tsugumi", use_route: :poll
|
||||||
|
response.status.should eq(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return 400 if post_id doesn't correspond to a poll post" do
|
||||||
|
log_in_user user1
|
||||||
|
post2 = create_post(topic: topic, raw: "Generic reply")
|
||||||
|
xhr :put, :vote, post_id: post2.id, option: "Chitoge", use_route: :poll
|
||||||
|
response.status.should eq(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should save votes correctly" do
|
||||||
|
log_in_user user1
|
||||||
|
xhr :put, :vote, post_id: post.id, option: "Chitoge", use_route: :poll
|
||||||
|
PollPlugin::Poll.new(post).get_vote(user1).should eq("Chitoge")
|
||||||
|
|
||||||
|
log_in_user user2
|
||||||
|
xhr :put, :vote, post_id: post.id, option: "Onodera", use_route: :poll
|
||||||
|
PollPlugin::Poll.new(post).get_vote(user2).should eq("Onodera")
|
||||||
|
|
||||||
|
PollPlugin::Poll.new(post).details["Chitoge"].should eq(1)
|
||||||
|
PollPlugin::Poll.new(post).details["Onodera"].should eq(1)
|
||||||
|
|
||||||
|
xhr :put, :vote, post_id: post.id, option: "Chitoge", use_route: :poll
|
||||||
|
PollPlugin::Poll.new(post).get_vote(user2).should eq("Chitoge")
|
||||||
|
|
||||||
|
PollPlugin::Poll.new(post).details["Chitoge"].should eq(2)
|
||||||
|
PollPlugin::Poll.new(post).details["Onodera"].should eq(0)
|
||||||
|
end
|
||||||
|
end
|
51
plugins/poll/spec/poll_plugin/poll_spec.rb
Normal file
51
plugins/poll/spec/poll_plugin/poll_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe PollPlugin::Poll do
|
||||||
|
let(:topic) { create_topic(title: "Poll: Chitoge vs Onodera") }
|
||||||
|
let(:post) { create_post(topic: topic, raw: "Pick one.\n\n[poll]\n* Chitoge\n* Onodera\n[/poll]") }
|
||||||
|
let(:poll) { PollPlugin::Poll.new(post) }
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it "should detect poll post correctly" do
|
||||||
|
expect(poll.is_poll?).to be_true
|
||||||
|
post2 = create_post(topic: topic, raw: "This is a generic reply.")
|
||||||
|
expect(PollPlugin::Poll.new(post2).is_poll?).to be_false
|
||||||
|
post.topic.title = "Not a poll"
|
||||||
|
expect(poll.is_poll?).to be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should get options correctly" do
|
||||||
|
expect(poll.options).to eq(["Chitoge", "Onodera"])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should get details correctly" do
|
||||||
|
expect(poll.details).to eq({"Chitoge" => 0, "Onodera" => 0})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should set details correctly" do
|
||||||
|
poll.set_details!({})
|
||||||
|
poll.details.should eq({})
|
||||||
|
PollPlugin::Poll.new(post).details.should eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should get and set votes correctly" do
|
||||||
|
poll.get_vote(user).should eq(nil)
|
||||||
|
poll.set_vote!(user, "Onodera")
|
||||||
|
poll.get_vote(user).should eq("Onodera")
|
||||||
|
poll.details["Onodera"].should eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should serialize correctly" do
|
||||||
|
poll.serialize(user).should eq({options: poll.details, selected: nil})
|
||||||
|
poll.set_vote!(user, "Onodera")
|
||||||
|
poll.serialize(user).should eq({options: poll.details, selected: "Onodera"})
|
||||||
|
poll.serialize(nil).should eq({options: poll.details, selected: nil})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should serialize to nil if there are no poll options" do
|
||||||
|
topic = create_topic(title: "This is not a poll topic")
|
||||||
|
post = create_post(topic: topic, raw: "no options in the content")
|
||||||
|
poll = PollPlugin::Poll.new(post)
|
||||||
|
poll.serialize(user).should eq(nil)
|
||||||
|
end
|
||||||
|
end
|
25
plugins/poll/spec/post_creator_spec.rb
Normal file
25
plugins/poll/spec/post_creator_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'post_creator'
|
||||||
|
|
||||||
|
describe PostCreator do
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
context "poll topic" do
|
||||||
|
it "cannot be created without a list of options" do
|
||||||
|
post = PostCreator.create(user, {title: "Poll: This is a poll", raw: "body does not contain a list"})
|
||||||
|
post.errors[:raw].should be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
it "cannot have options changed after 5 minutes" do
|
||||||
|
post = PostCreator.create(user, {title: "Poll: This is a poll", raw: "[poll]\n* option 1\n* option 2\n* option 3\n* option 4\n[/poll]"})
|
||||||
|
post.raw = "[poll]\n* option 1\n* option 2\n* option 3\n[/poll]"
|
||||||
|
post.valid?.should be_true
|
||||||
|
post.save
|
||||||
|
Timecop.freeze(Time.now + 6.minutes) do
|
||||||
|
post.raw = "[poll]\n* option 1\n* option 2\n* option 3\n* option 4\n[/poll]"
|
||||||
|
post.valid?.should be_false
|
||||||
|
post.errors[:raw].should be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user