start on automated story title and tagging suggestions
Rather than keep "poorly titled" and "poorly tagged" as reasons for flagging, make the user do the work of suggesting new ones. At some point, suggested taggings will flip to real taggings once they reach a certain count (to be determined later). This also has to take into account tagging sets that don't contain current tags, for when they need to be removed. For titles, I'm not yet sure how to handle this in an automated fashion except for the (probably rare) case of multiple users submitting the same exact thing, but at least collect them for now. Issue #207
This commit is contained in:
parent
700c63b936
commit
e940601a2f
|
@ -823,7 +823,7 @@ div#story_box #story_tags_a {
|
|||
div#story_box textarea {
|
||||
width: 600px;
|
||||
}
|
||||
div#story_box div.markdown_help_toggler {
|
||||
div#story_box div.actions {
|
||||
margin-left: 7em;
|
||||
width: 610px;
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@
|
|||
div#story_box button,
|
||||
div#story_box textarea,
|
||||
div#story_box #story_tags_a,
|
||||
div.markdown_help_toggler {
|
||||
div.actions {
|
||||
margin: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
class StoriesController < ApplicationController
|
||||
before_filter :require_logged_in_user_or_400,
|
||||
:only => [ :upvote, :downvote, :unvote, :hide, :unhide, :preview ]
|
||||
|
||||
before_filter :require_logged_in_user, :only => [ :destroy, :create, :edit,
|
||||
:fetch_url_title, :new ]
|
||||
|
||||
:fetch_url_title, :new, :suggest ]
|
||||
before_filter :find_user_story, :only => [ :destroy, :edit, :undelete,
|
||||
:update ]
|
||||
before_filter :find_story!, :only => [ :suggest, :submit_suggestions ]
|
||||
|
||||
def create
|
||||
@title = "Submit Story"
|
||||
|
@ -169,6 +168,33 @@ class StoriesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def suggest
|
||||
if (st = @story.suggested_taggings.where(:user_id => @user.id)).any?
|
||||
@story.tags_a = st.map{|st| st.tag.tag }
|
||||
end
|
||||
if tt = @story.suggested_titles.where(:user_id => @user.id).first
|
||||
@story.title = tt.title
|
||||
end
|
||||
end
|
||||
|
||||
def submit_suggestions
|
||||
ostory = @story.dup
|
||||
|
||||
@story.title = params[:story][:title]
|
||||
if @story.valid?
|
||||
if @story.title != ostory.title
|
||||
@story.save_suggested_title_for_user!(@story.title, @user)
|
||||
end
|
||||
if @story.tags_a.sort != params[:story][:tags_a].sort
|
||||
@story.save_suggested_tags_a_for_user!(params[:story][:tags_a], @user)
|
||||
end
|
||||
flash[:success] = "Your suggested changes have been noted."
|
||||
redirect_to ostory.comments_path
|
||||
else
|
||||
render :action => "suggest"
|
||||
end
|
||||
end
|
||||
|
||||
def undelete
|
||||
if !(@story.is_editable_by_user?(@user) &&
|
||||
@story.is_undeletable_by_user?(@user))
|
||||
|
@ -291,6 +317,13 @@ private
|
|||
story
|
||||
end
|
||||
|
||||
def find_story!
|
||||
@story = find_story
|
||||
if !@story
|
||||
raise ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
def find_user_story
|
||||
if @user.is_moderator?
|
||||
@story = Story.where(:short_id => params[:story_id] || params[:id]).first
|
||||
|
|
|
@ -8,6 +8,8 @@ class Story < ActiveRecord::Base
|
|||
:foreign_key => "merged_story_id"
|
||||
has_many :taggings,
|
||||
:autosave => true
|
||||
has_many :suggested_taggings
|
||||
has_many :suggested_titles
|
||||
has_many :comments,
|
||||
:inverse_of => :story
|
||||
has_many :tags, :through => :taggings
|
||||
|
@ -478,7 +480,8 @@ class Story < ActiveRecord::Base
|
|||
|
||||
@_tags_a = []
|
||||
def tags_a
|
||||
@_tags_a ||= self.taggings.map{|t| t.tag.tag }
|
||||
@_tags_a ||= self.taggings.reject{|t| t.marked_for_destruction?
|
||||
}.map{|t| t.tag.tag }
|
||||
end
|
||||
|
||||
def tags_a=(new_tag_names_a)
|
||||
|
@ -501,6 +504,47 @@ class Story < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def save_suggested_tags_a_for_user!(new_tag_names_a, user)
|
||||
st = self.suggested_taggings.where(:user_id => user.id)
|
||||
|
||||
st.each do |tagging|
|
||||
if !new_tag_names_a.include?(tagging.tag.tag)
|
||||
tagging.destroy
|
||||
end
|
||||
end
|
||||
|
||||
st.reload
|
||||
|
||||
new_tag_names_a.each do |tag_name|
|
||||
# XXX: AR bug? st.exists?(:tag => tag_name) does not work
|
||||
if tag_name.to_s != "" && !st.map{|x| x.tag.tag }.include?(tag_name)
|
||||
if (t = Tag.active.where(:tag => tag_name).first) &&
|
||||
t.valid_for?(user)
|
||||
tg = self.suggested_taggings.build
|
||||
tg.user_id = user.id
|
||||
tg.tag_id = t.id
|
||||
tg.save!
|
||||
|
||||
st.reload
|
||||
else
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: promote suggested tags to real one when count reaches something
|
||||
end
|
||||
|
||||
def save_suggested_title_for_user!(title, user)
|
||||
st = self.suggested_titles.where(:user_id => user.id).first
|
||||
if !st
|
||||
st = self.suggested_titles.build
|
||||
st.user_id = user.id
|
||||
end
|
||||
st.title = title
|
||||
st.save!
|
||||
end
|
||||
|
||||
def title=(t)
|
||||
# change unicode whitespace characters into real spaces
|
||||
self[:title] = t.strip
|
||||
|
|
5
app/models/suggested_tagging.rb
Normal file
5
app/models/suggested_tagging.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class SuggestedTagging < ActiveRecord::Base
|
||||
belongs_to :tag
|
||||
belongs_to :story
|
||||
belongs_to :user
|
||||
end
|
4
app/models/suggested_title.rb
Normal file
4
app/models/suggested_title.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class SuggestedTitle < ActiveRecord::Base
|
||||
belongs_to :story
|
||||
belongs_to :user
|
||||
end
|
|
@ -15,8 +15,6 @@ class Vote < ActiveRecord::Base
|
|||
STORY_REASONS = {
|
||||
"O" => "Off-topic",
|
||||
"A" => "Already Posted",
|
||||
"T" => "Poorly Tagged",
|
||||
"L" => "Poorly Titled",
|
||||
"S" => "Spam",
|
||||
"" => "Cancel",
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<% end %>
|
||||
|
||||
<div class="box">
|
||||
<% unless defined?(suggesting) %>
|
||||
<div class="boxline">
|
||||
<% if f.object.url_is_editable_by_user?(@user) %>
|
||||
<%= f.label :url, "URL:", :class => "required" %>
|
||||
|
@ -38,6 +39,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="boxline">
|
||||
<%= f.label :title, "Title:", :class => "required" %>
|
||||
|
@ -63,6 +65,7 @@
|
|||
f.object.tags_a), {}, { :multiple => true } %>
|
||||
</div>
|
||||
|
||||
<% unless defined?(suggesting) %>
|
||||
<div class="boxline">
|
||||
<%= f.label :description, "Text:", :class => "required" %>
|
||||
<%= f.text_area :description, :rows => 15,
|
||||
|
@ -70,7 +73,7 @@
|
|||
:autocomplete => "off" %>
|
||||
</div>
|
||||
|
||||
<div class="boxline markdown_help_toggler">
|
||||
<div class="boxline actions markdown_help_toggler">
|
||||
<a href="#" id="story_guidelines_toggler">
|
||||
Story submission guidelines
|
||||
</a>
|
||||
|
@ -120,7 +123,9 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% unless defined?(suggesting) %>
|
||||
<div class="box">
|
||||
<div class="boxline">
|
||||
<%= f.label :user_is_author, "Author:", :class => "required" %>
|
||||
|
@ -140,3 +145,4 @@
|
|||
});
|
||||
});
|
||||
</script>
|
||||
<% end %>
|
||||
|
|
|
@ -127,6 +127,9 @@ class="story <%= story.vote && story.vote[:vote] == 1 ? "upvoted" : "" %>
|
|||
:confirm => "Are you sure you want to delete this story?" } %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% elsif @user %>
|
||||
| <%= link_to "suggest", story_suggest_path(story.short_id),
|
||||
:class => "suggester" %>
|
||||
<% end %>
|
||||
<% if !story.is_gone? && @user %>
|
||||
<% if @user && story.vote && story.vote[:vote] == -1 %>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<p></p>
|
||||
|
||||
<div class="box">
|
||||
<div class="boxline markdown_help_toggler">
|
||||
<div class="boxline actions markdown_help_toggler">
|
||||
<div class="markdown_help_label">
|
||||
Markdown formatting available
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<p></p>
|
||||
|
||||
<div class="box">
|
||||
<div class="boxline markdown_help_toggler">
|
||||
<div class="boxline actions markdown_help_toggler">
|
||||
<div class="markdown_help_label">
|
||||
Markdown formatting available
|
||||
</div>
|
||||
|
|
21
app/views/stories/suggest.html.erb
Normal file
21
app/views/stories/suggest.html.erb
Normal file
|
@ -0,0 +1,21 @@
|
|||
<div class="box" id="story_box">
|
||||
<div class="legend">
|
||||
Suggest Story Changes
|
||||
</div>
|
||||
|
||||
<%= form_for @story, :url => story_suggest_path(@story.short_id),
|
||||
:method => :post, :html => { :id => "edit_story" } do |f| %>
|
||||
<%= render :partial => "stories/form", :locals => { :story => @story,
|
||||
:f => f, :suggesting => true } %>
|
||||
|
||||
<p></p>
|
||||
|
||||
<div class="box">
|
||||
<div class="boxline actions">
|
||||
<%= submit_tag "Suggest Changes" %>
|
||||
or <a href="<%= story_path(@story.short_id) %>">cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -57,6 +57,8 @@ Lobsters::Application.routes.draw do
|
|||
post "undelete"
|
||||
post "hide"
|
||||
post "unhide"
|
||||
get "suggest"
|
||||
post "suggest", :action => "submit_suggestions"
|
||||
end
|
||||
post "/stories/fetch_url_attributes", :format => "json"
|
||||
post "/stories/preview" => "stories#preview"
|
||||
|
|
9
db/migrate/20151015005101_add_suggested_taggings.rb
Normal file
9
db/migrate/20151015005101_add_suggested_taggings.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class AddSuggestedTaggings < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :suggested_taggings do |t|
|
||||
t.integer :story_id
|
||||
t.integer :tag_id
|
||||
t.integer :user_id
|
||||
end
|
||||
end
|
||||
end
|
9
db/migrate/20151015011231_add_suggested_titles.rb
Normal file
9
db/migrate/20151015011231_add_suggested_titles.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class AddSuggestedTitles < ActiveRecord::Migration
|
||||
def change
|
||||
create_table "suggested_titles" do |t|
|
||||
t.integer :story_id
|
||||
t.integer :user_id
|
||||
t.string :title, :limit => 150, :null => false
|
||||
end
|
||||
end
|
||||
end
|
14
db/schema.rb
14
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150730225352) do
|
||||
ActiveRecord::Schema.define(version: 20151015011231) do
|
||||
|
||||
create_table "comments", force: true do |t|
|
||||
t.datetime "created_at", null: false
|
||||
|
@ -133,6 +133,18 @@ ActiveRecord::Schema.define(version: 20150730225352) do
|
|||
add_index "stories", ["twitter_id"], name: "index_stories_on_twitter_id", using: :btree
|
||||
add_index "stories", ["url"], name: "url", length: {"url"=>191}, using: :btree
|
||||
|
||||
create_table "suggested_taggings", force: true do |t|
|
||||
t.integer "story_id"
|
||||
t.integer "tag_id"
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
create_table "suggested_titles", force: true do |t|
|
||||
t.integer "story_id"
|
||||
t.integer "user_id"
|
||||
t.string "title", limit: 150, null: false
|
||||
end
|
||||
|
||||
create_table "tag_filters", force: true do |t|
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
|
Loading…
Reference in a new issue