FEATURE: remove star concept from Discourse

This commit is contained in:
Sam 2015-01-07 12:19:23 +11:00
parent fa8493118b
commit efc717c14a
35 changed files with 50 additions and 448 deletions

View File

@ -57,7 +57,6 @@
{{ render 'admin_report_counts' likes }} {{ render 'admin_report_counts' likes }}
{{ render 'admin_report_counts' flags }} {{ render 'admin_report_counts' flags }}
{{ render 'admin_report_counts' bookmarks }} {{ render 'admin_report_counts' bookmarks }}
{{ render 'admin_report_counts' starred }}
{{ render 'admin_report_counts' emails }} {{ render 'admin_report_counts' emails }}
{{/unless}} {{/unless}}
</table> </table>

View File

@ -165,7 +165,7 @@ var controllerOpts = {
var split = this.get('filter').split('/'); var split = this.get('filter').split('/');
if (split[0] !== 'new' && split[0] !== 'unread' && split[0] !== 'starred') { return; } if (split[0] !== 'new' && split[0] !== 'unread') { return; }
return I18n.t("topics.none.educate." + split[0], { return I18n.t("topics.none.educate." + split[0], {
userPrefsUrl: Discourse.getURL("/users/") + (Discourse.User.currentProp("username_lower")) + "/preferences" userPrefsUrl: Discourse.getURL("/users/") + (Discourse.User.currentProp("username_lower")) + "/preferences"

View File

@ -3,7 +3,6 @@ var PATH_BINDINGS = {
'g l': '/latest', 'g l': '/latest',
'g n': '/new', 'g n': '/new',
'g u': '/unread', 'g u': '/unread',
'g f': '/starred',
'g c': '/categories', 'g c': '/categories',
'g t': '/top' 'g t': '/top'
}, },

View File

@ -74,7 +74,7 @@ Discourse.NavItem.reopenClass({
if (!Discourse.Category.list() && testName === "categories") return null; if (!Discourse.Category.list() && testName === "categories") return null;
if (!Discourse.Site.currentProp('top_menu_items').contains(testName)) return null; if (!Discourse.Site.currentProp('top_menu_items').contains(testName)) return null;
var args = { name: name, hasIcon: name === "unread" || name === "starred" }; var args = { name: name, hasIcon: name === "unread" };
if (opts.category) { args.category = opts.category; } if (opts.category) { args.category = opts.category; }
if (opts.noSubcategories) { args.noSubcategories = true; } if (opts.noSubcategories) { args.noSubcategories = true; }
return Discourse.NavItem.create(args); return Discourse.NavItem.create(args);

View File

@ -172,14 +172,6 @@ Discourse.Topic = Discourse.Model.extend({
.then(function () { self.set('archetype', 'regular'); }); .then(function () { self.set('archetype', 'regular'); });
}, },
starTooltipKey: function() {
return this.get('starred') ? 'starred.help.unstar' : 'starred.help.star';
}.property('starred'),
starTooltip: function() {
return I18n.t(this.get('starTooltipKey'));
}.property('starTooltipKey'),
estimatedReadingTime: function() { estimatedReadingTime: function() {
var wordCount = this.get('word_count'); var wordCount = this.get('word_count');
if (!wordCount) return; if (!wordCount) return;
@ -188,15 +180,15 @@ Discourse.Topic = Discourse.Model.extend({
return Math.floor(wordCount / 500.0); return Math.floor(wordCount / 500.0);
}.property('word_count'), }.property('word_count'),
toggleStar: function() { toggleBookmark: function() {
var topic = this; var topic = this;
topic.toggleProperty('starred'); topic.toggleProperty('bookmarked');
return Discourse.ajax({ return Discourse.ajax({
url: "" + (this.get('url')) + "/star", url: "" + (this.get('url')) + "/bookmark",
type: 'PUT', type: 'PUT',
data: { starred: topic.get('starred') ? true : false } data: { bookmarked: topic.get('bookmarked') ? true : false }
}).then(null, function (error) { }).then(null, function (error) {
topic.toggleProperty('starred'); topic.toggleProperty('bookmarked');
if (error && error.responseText) { if (error && error.responseText) {
bootbox.alert($.parseJSON(error.responseText).errors); bootbox.alert($.parseJSON(error.responseText).errors);

View File

@ -16,7 +16,6 @@ var UserActionTypes = {
replies: 6, replies: 6,
mentions: 7, mentions: 7,
quotes: 9, quotes: 9,
starred: 10,
edits: 11, edits: 11,
messages_sent: 12, messages_sent: 12,
messages_received: 13 messages_received: 13
@ -127,8 +126,6 @@ Discourse.UserAction = Discourse.Model.extend({
case UserActionTypes.likes_given: case UserActionTypes.likes_given:
case UserActionTypes.likes_received: case UserActionTypes.likes_received:
return "likes"; return "likes";
case UserActionTypes.starred:
return "stars";
case UserActionTypes.edits: case UserActionTypes.edits:
return "edits"; return "edits";
case UserActionTypes.bookmarks: case UserActionTypes.bookmarks:
@ -205,7 +202,6 @@ Discourse.UserAction.reopenClass({
TO_COLLAPSE: [ TO_COLLAPSE: [
UserActionTypes.likes_given, UserActionTypes.likes_given,
UserActionTypes.likes_received, UserActionTypes.likes_received,
UserActionTypes.starred,
UserActionTypes.edits, UserActionTypes.edits,
UserActionTypes.bookmarks UserActionTypes.bookmarks
], ],
@ -213,7 +209,6 @@ Discourse.UserAction.reopenClass({
TO_SHOW: [ TO_SHOW: [
UserActionTypes.likes_given, UserActionTypes.likes_given,
UserActionTypes.likes_received, UserActionTypes.likes_received,
UserActionTypes.starred,
UserActionTypes.edits, UserActionTypes.edits,
UserActionTypes.bookmarks, UserActionTypes.bookmarks,
UserActionTypes.messages_sent, UserActionTypes.messages_sent,

View File

@ -1,9 +0,0 @@
import UserTopicListRoute from "discourse/routes/user-topic-list";
export default UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.starred,
model: function() {
return Discourse.TopicList.find('starred', { user_id: this.modelFor('user').get('id') });
}
});

View File

@ -7,7 +7,6 @@
<li>{{{i18n 'keyboard_shortcuts_help.jump_to.latest'}}}</li> <li>{{{i18n 'keyboard_shortcuts_help.jump_to.latest'}}}</li>
<li>{{{i18n 'keyboard_shortcuts_help.jump_to.new'}}}</li> <li>{{{i18n 'keyboard_shortcuts_help.jump_to.new'}}}</li>
<li>{{{i18n 'keyboard_shortcuts_help.jump_to.unread'}}}</li> <li>{{{i18n 'keyboard_shortcuts_help.jump_to.unread'}}}</li>
<li>{{{i18n 'keyboard_shortcuts_help.jump_to.starred'}}}</li>
<li>{{{i18n 'keyboard_shortcuts_help.jump_to.categories'}}}</li> <li>{{{i18n 'keyboard_shortcuts_help.jump_to.categories'}}}</li>
<li>{{{i18n 'keyboard_shortcuts_help.jump_to.top'}}}</li> <li>{{{i18n 'keyboard_shortcuts_help.jump_to.top'}}}</li>
</ul> </ul>

View File

@ -54,7 +54,6 @@ export default Ember.Component.extend(StringBuffer, {
case Discourse.UserAction.TYPES.bookmarks: return "bookmark"; case Discourse.UserAction.TYPES.bookmarks: return "bookmark";
case Discourse.UserAction.TYPES.edits: return "pencil"; case Discourse.UserAction.TYPES.edits: return "pencil";
case Discourse.UserAction.TYPES.replies: return "reply"; case Discourse.UserAction.TYPES.replies: return "reply";
case Discourse.UserAction.TYPES.starred: return "star";
} }
}.property("content.action_type") }.property("content.action_type")
}); });

View File

@ -1,21 +0,0 @@
import ButtonView from 'discourse/views/button';
export default ButtonView.extend({
classNames: ['star'],
textKey: 'starred.title',
helpKeyBinding: 'controller.starTooltipKey',
attributeBindings: ['disabled'],
rerenderTriggers: ['controller.starred'],
click: function() {
this.get('controller').send('toggleStar');
},
renderIcon: function(buffer) {
buffer.push("<i class='fa fa-star " +
(this.get('controller.starred') ? ' starred' : '') +
"'></i>");
}
});

View File

@ -1,7 +1,6 @@
import TopicAdminMenuButton from 'discourse/views/topic-admin-menu-button'; import TopicAdminMenuButton from 'discourse/views/topic-admin-menu-button';
import LoginReplyButton from 'discourse/views/login-reply-button'; import LoginReplyButton from 'discourse/views/login-reply-button';
import FlagTopicButton from 'discourse/views/flag-topic-button'; import FlagTopicButton from 'discourse/views/flag-topic-button';
import StarButton from 'discourse/views/star-button';
import ShareButton from 'discourse/views/share-button'; import ShareButton from 'discourse/views/share-button';
import InviteReplyButton from 'discourse/views/invite-reply-button'; import InviteReplyButton from 'discourse/views/invite-reply-button';
import ReplyButton from 'discourse/views/reply-button'; import ReplyButton from 'discourse/views/reply-button';
@ -30,7 +29,6 @@ export default DiscourseContainerView.extend({
if (this.get('topic.details.can_invite_to')) { if (this.get('topic.details.can_invite_to')) {
this.attachViewClass(InviteReplyButton); this.attachViewClass(InviteReplyButton);
} }
this.attachViewClass(StarButton);
this.attachViewClass(ShareButton); this.attachViewClass(ShareButton);
if (this.get('topic.details.can_flag_topic')) { if (this.get('topic.details.can_flag_topic')) {
this.attachViewClass(FlagTopicButton); this.attachViewClass(FlagTopicButton);

View File

@ -10,9 +10,6 @@
margin-right: 4px; margin-right: 4px;
font: 1.071em/0.9 "FontAwesome"; font: 1.071em/0.9 "FontAwesome";
} }
.has-icon .starred:before {
content: "\f005";
}
} }
} }

View File

@ -36,24 +36,12 @@ body {
} }
} }
#main { #main {
.fa-star.starred {
color: $danger;
}
a.star { a.star {
color: dark-light-diff($secondary, $primary, 80%, -20%); color: dark-light-diff($secondary, $primary, 80%, -20%);
&:before { &:before {
font-family: "FontAwesome"; font-family: "FontAwesome";
content: "\f005"; content: "\f005";
} }
&.starred {
color: $danger;
@include hover {
opacity: 1;
&:before {
content: "\f005";
}
}
}
@include hover { @include hover {
opacity: 0.6; opacity: 0.6;
} }

View File

@ -551,12 +551,6 @@ video {
line-height: 1.3em; line-height: 1.3em;
} }
a.star {
margin: 0 7px 20px 2px;
color: dark-light-diff($secondary, $primary, 80%, -20%) !important;
}
a.star.starred {color: $danger !important;}
.topic-statuses { .topic-statuses {
margin-top: -2px; margin-top: -2px;
} }

View File

@ -18,36 +18,6 @@ body {
} }
} }
#main { #main {
.fa-star.starred {
color: $danger;
}
a.star {
display: inline-block;
font-size: 1.429em;
color: scale-color($primary, $lightness: 75%);
margin-right: 8px;
margin-top: 4px;
&:before {
font-family: "FontAwesome";
content: "\f005";
}
&.starred {
color: $danger;
@include hover {
opacity: 1;
&:before {
content: "\f005";
}
}
}
@include hover {
opacity: 0.6;
}
&:active {
opacity: 1;
}
}
img.avatar { img.avatar {
&.header { &.header {
width: 45px; width: 45px;

View File

@ -166,14 +166,6 @@ class TopicsController < ApplicationController
render nothing: true render nothing: true
end end
def star
@topic = Topic.find_by(id: params[:topic_id].to_i)
guardian.ensure_can_see!(@topic)
@topic.toggle_star(current_user, params[:starred] == 'true')
render nothing: true
end
def mute def mute
toggle_mute toggle_mute
end end

View File

@ -11,7 +11,6 @@ class AdminDashboardData
'users_by_trust_level', 'users_by_trust_level',
'likes', 'likes',
'bookmarks', 'bookmarks',
'starred',
'emails', 'emails',
'user_to_user_private_messages', 'user_to_user_private_messages',
'system_private_messages', 'system_private_messages',

View File

@ -91,13 +91,7 @@ class Report
end end
end end
def self.report_starred(report)
basic_report_about report, Topic, :starred_counts_per_day, default_days
add_counts report, TopicUser.where(starred: true), 'topic_users.starred_at'
end
# Post action counts: # Post action counts:
def self.report_flags(report) def self.report_flags(report)
basic_report_about report, PostAction, :flag_count_by_date, report.start_date, report.end_date basic_report_about report, PostAction, :flag_count_by_date, report.start_date, report.end_date
add_counts report, PostAction.where(post_action_type_id: PostActionType.flag_types.values), 'post_actions.created_at' add_counts report, PostAction.where(post_action_type_id: PostActionType.flag_types.values), 'post_actions.created_at'

View File

@ -141,13 +141,6 @@ class Topic < ActiveRecord::Base
WHERE #{condition[0]})", condition[1]) WHERE #{condition[0]})", condition[1])
} }
# Helps us limit how many topics can be starred in a day
class StarLimiter < RateLimiter
def initialize(user)
super(user, "starred:#{Date.today}", SiteSetting.max_stars_per_day, 1.day.to_i)
end
end
attr_accessor :ignore_category_auto_close attr_accessor :ignore_category_auto_close
attr_accessor :skip_callbacks attr_accessor :skip_callbacks
@ -612,27 +605,6 @@ class Topic < ActiveRecord::Base
@participants_summary ||= TopicParticipantsSummary.new(self, options).summary @participants_summary ||= TopicParticipantsSummary.new(self, options).summary
end end
# Enable/disable the star on the topic
def toggle_star(user, starred)
Topic.transaction do
TopicUser.change(user, id, {starred: starred}.merge( starred ? {starred_at: DateTime.now, unstarred_at: nil} : {unstarred_at: DateTime.now}))
# Update the star count
exec_sql "UPDATE topics
SET star_count = (SELECT COUNT(*)
FROM topic_users AS ftu
WHERE ftu.topic_id = topics.id
AND ftu.starred = true)
WHERE id = ?", id
if starred
StarLimiter.new(user).performed!
else
StarLimiter.new(user).rollback!
end
end
end
def make_banner!(user) def make_banner!(user)
# only one banner at the same time # only one banner at the same time
previous_banner = Topic.where(archetype: Archetype.banner).first previous_banner = Topic.where(archetype: Archetype.banner).first
@ -662,10 +634,6 @@ class Topic < ActiveRecord::Base
} }
end end
def self.starred_counts_per_day(sinceDaysAgo=30)
TopicUser.starred_since(sinceDaysAgo).by_date_starred.count
end
# Even if the slug column in the database is null, topic.slug will return something: # Even if the slug column in the database is null, topic.slug will return something:
def slug def slug
unless slug = read_attribute(:slug) unless slug = read_attribute(:slug)

View File

@ -2,9 +2,6 @@ class TopicUser < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :topic belongs_to :topic
scope :starred_since, lambda { |sinceDaysAgo| where('starred_at > ?', sinceDaysAgo.days.ago) }
scope :by_date_starred, -> { group('date(starred_at)').order('date(starred_at)') }
scope :tracking, lambda { |topic_id| scope :tracking, lambda { |topic_id|
where(topic_id: topic_id) where(topic_id: topic_id)
.where("COALESCE(topic_users.notification_level, :regular) >= :tracking", .where("COALESCE(topic_users.notification_level, :regular) >= :tracking",
@ -86,8 +83,6 @@ class TopicUser < ActiveRecord::Base
TopicUser.transaction do TopicUser.transaction do
attrs = attrs.dup attrs = attrs.dup
attrs[:starred_at] = DateTime.now if attrs[:starred_at].nil? && attrs[:starred]
if attrs[:notification_level] if attrs[:notification_level]
attrs[:notifications_changed_at] ||= DateTime.now attrs[:notifications_changed_at] ||= DateTime.now
attrs[:notifications_reason_id] ||= TopicUser.notification_reasons[:user_changed] attrs[:notifications_reason_id] ||= TopicUser.notification_reasons[:user_changed]

View File

@ -14,7 +14,6 @@ class UserAction < ActiveRecord::Base
RESPONSE= 6 RESPONSE= 6
MENTION = 7 MENTION = 7
QUOTE = 9 QUOTE = 9
STAR = 10
EDIT = 11 EDIT = 11
NEW_PRIVATE_MESSAGE = 12 NEW_PRIVATE_MESSAGE = 12
GOT_PRIVATE_MESSAGE = 13 GOT_PRIVATE_MESSAGE = 13
@ -30,7 +29,6 @@ class UserAction < ActiveRecord::Base
MENTION, MENTION,
QUOTE, QUOTE,
BOOKMARK, BOOKMARK,
STAR,
EDIT EDIT
].each_with_index.to_a.flatten] ].each_with_index.to_a.flatten]
@ -240,35 +238,8 @@ SQL
builder.exec builder.exec
end end
def self.synchronize_starred
exec_sql("
DELETE FROM user_actions ua
WHERE action_type = :star
AND NOT EXISTS (
SELECT 1 FROM topic_users tu
WHERE
tu.user_id = ua.user_id AND
tu.topic_id = ua.target_topic_id AND
starred
)", star: UserAction::STAR)
exec_sql("INSERT INTO user_actions
(action_type, user_id, target_topic_id, target_post_id, acting_user_id, created_at, updated_at)
SELECT :star, tu.user_id, tu.topic_id, -1, tu.user_id, tu.starred_at, tu.starred_at
FROM topic_users tu
WHERE starred AND NOT EXISTS(
SELECT 1 FROM user_actions ua
WHERE tu.user_id = ua.user_id AND
tu.topic_id = ua.target_topic_id AND
ua.action_type = :star
)
", star: UserAction::STAR)
end
def self.ensure_consistency! def self.ensure_consistency!
self.synchronize_target_topic_ids self.synchronize_target_topic_ids
self.synchronize_starred
end end
def self.update_like_count(user_id, action_type, delta) def self.update_like_count(user_id, action_type, delta)
@ -294,7 +265,7 @@ SQL
end end
unless (guardian.user && guardian.user.id == user_id) || guardian.is_staff? unless (guardian.user && guardian.user.id == user_id) || guardian.is_staff?
builder.where("a.action_type not in (#{BOOKMARK},#{STAR})") builder.where("a.action_type not in (#{BOOKMARK})")
builder.where("t.visible") builder.where("t.visible")
end end

View File

@ -9,27 +9,6 @@ class UserActionObserver < ActiveRecord::Observer
log_topic(model) log_topic(model)
when (model.is_a?(Post)) when (model.is_a?(Post))
log_post(model) log_post(model)
when (model.is_a?(TopicUser))
log_topic_user(model)
end
end
def log_topic_user(model)
action = UserAction::STAR
row = {
action_type: action,
user_id: model.user_id,
acting_user_id: model.user_id,
target_topic_id: model.topic_id,
target_post_id: -1,
created_at: model.starred_at
}
if model.starred
UserAction.log_action!(row)
else
UserAction.remove_action!(row)
end end
end end

View File

@ -2,7 +2,6 @@ class TopicListItemSerializer < ListableTopicSerializer
attributes :views, attributes :views,
:like_count, :like_count,
:starred,
:has_summary, :has_summary,
:archetype, :archetype,
:last_poster_username, :last_poster_username,
@ -13,12 +12,6 @@ class TopicListItemSerializer < ListableTopicSerializer
has_many :posters, serializer: TopicPosterSerializer, embed: :objects has_many :posters, serializer: TopicPosterSerializer, embed: :objects
has_many :participants, serializer: TopicPosterSerializer, embed: :objects has_many :participants, serializer: TopicPosterSerializer, embed: :objects
def starred
object.user_data.starred?
end
alias :include_starred? :has_user_data
def posters def posters
object.posters || [] object.posters || []
end end

View File

@ -29,7 +29,6 @@ class TopicViewSerializer < ApplicationSerializer
attributes :draft, attributes :draft,
:draft_key, :draft_key,
:draft_sequence, :draft_sequence,
:starred,
:posted, :posted,
:unpinned, :unpinned,
:pinned_globally, :pinned_globally,
@ -145,11 +144,6 @@ class TopicViewSerializer < ApplicationSerializer
object.topic_user.present? object.topic_user.present?
end end
def starred
object.topic_user.starred?
end
alias_method :include_starred?, :has_topic_user?
def highest_post_number def highest_post_number
object.highest_post_number object.highest_post_number
end end

View File

@ -785,12 +785,6 @@ en:
not_logged_in_user: 'user page with summary of current activity and preferences' not_logged_in_user: 'user page with summary of current activity and preferences'
current_user: 'go to your user page' current_user: 'go to your user page'
starred:
title: 'Star'
help:
star: 'add this topic to your starred list'
unstar: 'remove this topic from your starred list'
topics: topics:
bulk: bulk:
reset_read: "Reset Read" reset_read: "Reset Read"
@ -811,7 +805,6 @@ en:
other: "You have selected <b>{{count}}</b> topics." other: "You have selected <b>{{count}}</b> topics."
none: none:
starred: "You have no starred topics."
unread: "You have no unread topics." unread: "You have no unread topics."
new: "You have no new topics." new: "You have no new topics."
read: "You haven't read any topics yet." read: "You haven't read any topics yet."
@ -823,7 +816,6 @@ en:
educate: educate:
new: '<p>Your new topics appear here.</p><p>By default, topics are considered new and will show a <span class="badge new-topic badge-notification" style="vertical-align:middle;line-height:inherit;">new</span> indicator if they were created in the last 2 days.</p><p>You can change this in your <a href="%{userPrefsUrl}">preferences</a>.</p>' new: '<p>Your new topics appear here.</p><p>By default, topics are considered new and will show a <span class="badge new-topic badge-notification" style="vertical-align:middle;line-height:inherit;">new</span> indicator if they were created in the last 2 days.</p><p>You can change this in your <a href="%{userPrefsUrl}">preferences</a>.</p>'
unread: '<p>Your unread topics appear here.</p><p>By default, topics are considered unread and will show unread counts <span class="badge new-posts badge-notification">1</span> if you:</p><ul><li>Created the topic</li><li>Replied to the topic</li><li>Read the topic for more than 4 minutes</li></ul><p>Or if you have explicitly set the topic to Tracked or Watched via the notification control at the bottom of each topic.</p><p>You can change this in your <a href="%{userPrefsUrl}">preferences</a>.</p>' unread: '<p>Your unread topics appear here.</p><p>By default, topics are considered unread and will show unread counts <span class="badge new-posts badge-notification">1</span> if you:</p><ul><li>Created the topic</li><li>Replied to the topic</li><li>Read the topic for more than 4 minutes</li></ul><p>Or if you have explicitly set the topic to Tracked or Watched via the notification control at the bottom of each topic.</p><p>You can change this in your <a href="%{userPrefsUrl}">preferences</a>.</p>'
starred: '<p>Your starred topics appear here.</p><p>To star or unstar a topic, use:</p><ul><li>the <i class="fa fa-star"></i> next to any topic title</li><li>the Star button at the bottom of each topic</li></ul>'
bottom: bottom:
latest: "There are no more latest topics." latest: "There are no more latest topics."
hot: "There are no more hot topics." hot: "There are no more hot topics."
@ -831,7 +823,6 @@ en:
read: "There are no more read topics." read: "There are no more read topics."
new: "There are no more new topics." new: "There are no more new topics."
unread: "There are no more unread topics." unread: "There are no more unread topics."
starred: "There are no more starred topics."
category: "There are no more {{category}} topics." category: "There are no more {{category}} topics."
top: "There are no more top topics." top: "There are no more top topics."
@ -1433,9 +1424,6 @@ en:
hot: hot:
title: "Hot" title: "Hot"
help: "a selection of the hottest topics" help: "a selection of the hottest topics"
starred:
title: "Starred"
help: "topics you starred"
read: read:
title: "Read" title: "Read"
help: "topics you've read, in the order that you last read them" help: "topics you've read, in the order that you last read them"
@ -2217,7 +2205,6 @@ en:
latest: '<b>g</b>, <b>l</b> Latest' latest: '<b>g</b>, <b>l</b> Latest'
new: '<b>g</b>, <b>n</b> New' new: '<b>g</b>, <b>n</b> New'
unread: '<b>g</b>, <b>u</b> Unread' unread: '<b>g</b>, <b>u</b> Unread'
starred: '<b>g</b>, <b>f</b> Starred'
categories: '<b>g</b>, <b>c</b> Categories' categories: '<b>g</b>, <b>c</b> Categories'
top: '<b>g</b>, <b>t</b> Top' top: '<b>g</b>, <b>t</b> Top'
navigation: navigation:

View File

@ -0,0 +1,29 @@
class RemoveStars < ActiveRecord::Migration
def up
r = execute <<SQL
INSERT INTO post_actions(user_id, post_id, post_action_type_id, created_at, updated_at)
SELECT tu.user_id, p.id, 1, coalesce(tu.starred_at, now()), coalesce(tu.starred_at, now())
FROM topic_users tu
JOIN posts p ON p.topic_id = tu.topic_id AND p.post_number = 1
LEFT JOIN post_actions pa ON
pa.post_id = p.id AND
pa.user_id = tu.user_id AND
pa.post_action_type_id = 1
WHERE pa.post_id IS NULL AND tu.starred
SQL
puts "#{r.cmd_tuples} stars were converted to bookmarks!"
execute <<SQL
DELETE FROM user_actions WHERE action_type = 10
SQL
remove_column :topic_users, :starred
remove_column :topic_users, :starred_at
remove_column :topic_users, :unstarred_at
remove_column :topics, :star_count
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -56,7 +56,7 @@ module Discourse
class CSRF < Exception; end class CSRF < Exception; end
def self.filters def self.filters
@filters ||= [:latest, :unread, :new, :starred, :read, :posted] @filters ||= [:latest, :unread, :new, :read, :posted]
end end
def self.feed_filters def self.feed_filters

View File

@ -69,11 +69,6 @@ class TopicQuery
create_list(:latest, {}, latest_results) create_list(:latest, {}, latest_results)
end end
# The starred topics
def list_starred
create_list(:starred) {|topics| topics.where('tu.starred') }
end
def list_read def list_read
create_list(:read, unordered: true) do |topics| create_list(:read, unordered: true) do |topics|
topics.order('COALESCE(tu.last_visited_at, topics.bumped_at) DESC') topics.order('COALESCE(tu.last_visited_at, topics.bumped_at) DESC')

View File

@ -285,27 +285,6 @@ describe TopicQuery do
end end
context 'list_starred' do
let(:topic) { Fabricate(:topic) }
it "returns no results when the user hasn't starred any topics" do
topic_query.list_starred.topics.should be_blank
end
context 'with a starred topic' do
before do
topic.toggle_star(user, true)
end
it "returns the topic after it has been starred" do
topic_query.list_starred.topics.should == [topic]
end
end
end
context 'list_new' do context 'list_new' do
context 'without a new topic' do context 'without a new topic' do
@ -386,11 +365,6 @@ describe TopicQuery do
end end
context "but interacted with" do context "but interacted with" do
it "is not included if starred" do
other_users_topic.toggle_star(user, true)
topics.should be_blank
end
it "is not included if read" do it "is not included if read" do
TopicUser.update_last_read(user, other_users_topic.id, 0, 0) TopicUser.update_last_read(user, other_users_topic.id, 0, 0)

View File

@ -184,22 +184,6 @@ describe ListController do
end end
end end
context 'starred' do
it 'raises an error when not logged in' do
lambda { xhr :get, :starred }.should raise_error(Discourse::NotLoggedIn)
end
context 'when logged in' do
before do
log_in_user(@user)
xhr :get, :starred
end
it { should respond_with(:success) }
end
end
context 'read' do context 'read' do
it 'raises an error when not logged in' do it 'raises an error when not logged in' do
lambda { xhr :get, :read }.should raise_error(Discourse::NotLoggedIn) lambda { xhr :get, :read }.should raise_error(Discourse::NotLoggedIn)

View File

@ -436,49 +436,10 @@ describe TopicsController do
@topic = Fabricate(:topic, user: log_in) @topic = Fabricate(:topic, user: log_in)
end end
it "changes the user's starred flag when the parameter is present" do
Topic.any_instance.expects(:toggle_mute).with(@topic.user)
xhr :put, :mute, topic_id: @topic.id, starred: 'true'
end
it "removes the user's starred flag when the parameter is not true" do
Topic.any_instance.expects(:toggle_mute).with(@topic.user)
xhr :put, :unmute, topic_id: @topic.id, starred: 'false'
end
end end
end end
describe 'star' do
it 'needs you to be logged in' do
lambda { xhr :put, :star, topic_id: 1, starred: true }.should raise_error(Discourse::NotLoggedIn)
end
describe 'when logged in' do
before do
@topic = Fabricate(:topic, user: log_in)
end
it "ensures the user can see the topic" do
Guardian.any_instance.expects(:can_see?).with(@topic).returns(false)
xhr :put, :star, topic_id: @topic.id, starred: 'true'
response.should be_forbidden
end
it "changes the user's starred flag when the parameter is present" do
Topic.any_instance.expects(:toggle_star).with(@topic.user, true)
xhr :put, :star, topic_id: @topic.id, starred: 'true'
end
it "removes the user's starred flag when the parameter is not true" do
Topic.any_instance.expects(:toggle_star).with(@topic.user, false)
xhr :put, :star, topic_id: @topic.id, starred: 'false'
end
end
end
describe 'recover' do describe 'recover' do
it "won't allow us to recover a topic when we're not logged in" do it "won't allow us to recover a topic when we're not logged in" do
lambda { xhr :put, :recover, topic_id: 1 }.should raise_error(Discourse::NotLoggedIn) lambda { xhr :put, :recover, topic_id: 1 }.should raise_error(Discourse::NotLoggedIn)

View File

@ -1,4 +1,4 @@
Fabricator(:user_action) do Fabricator(:user_action) do
user user
action_type UserAction::STAR action_type UserAction::BOOKMARK
end end

View File

@ -562,70 +562,6 @@ describe Topic do
end end
end end
describe 'toggle_star' do
shared_examples_for "adding a star to a topic" do
it 'triggers a forum topic user change with true' do
# otherwise no chance the mock will work
freeze_time
TopicUser.expects(:change).with(@user, @topic.id, starred: true, starred_at: DateTime.now, unstarred_at: nil)
@topic.toggle_star(@user, true)
end
it 'increases the star_count of the forum topic' do
expect {
@topic.toggle_star(@user, true)
@topic.reload
}.to change(@topic, :star_count).by(1)
end
it 'triggers the rate limiter' do
Topic::StarLimiter.any_instance.expects(:performed!)
@topic.toggle_star(@user, true)
end
end
before do
@topic = Fabricate(:topic)
@user = @topic.user
end
it_should_behave_like "adding a star to a topic"
describe 'removing a star' do
before do
@topic.toggle_star(@user, true)
@topic.reload
end
it 'rolls back the rate limiter' do
Topic::StarLimiter.any_instance.expects(:rollback!)
@topic.toggle_star(@user, false)
end
it 'triggers a forum topic user change with false' do
freeze_time
TopicUser.expects(:change).with(@user, @topic.id, starred: false, unstarred_at: DateTime.now)
@topic.toggle_star(@user, false)
end
it 'reduces the star_count' do
expect {
@topic.toggle_star(@user, false)
@topic.reload
}.to change(@topic, :star_count).by(-1)
end
describe 'and adding a star again' do
before do
@topic.toggle_star(@user, false)
@topic.reload
end
it_should_behave_like "adding a star to a topic"
end
end
end
describe "banner" do describe "banner" do
let(:topic) { Fabricate(:topic) } let(:topic) { Fabricate(:topic) }

View File

@ -20,14 +20,14 @@ describe TopicUser do
let(:topic_new_user) { TopicUser.get(topic, new_user)} let(:topic_new_user) { TopicUser.get(topic, new_user)}
let(:yesterday) { DateTime.now.yesterday } let(:yesterday) { DateTime.now.yesterday }
def ensure_topic_user
TopicUser.change(user, topic, last_emailed_post_number: 1)
end
describe "unpinned" do describe "unpinned" do
before do
TopicUser.change(user, topic, {starred_at: yesterday})
end
it "defaults to blank" do it "defaults to blank" do
ensure_topic_user
topic_user.cleared_pinned_at.should be_blank topic_user.cleared_pinned_at.should be_blank
end end
@ -37,19 +37,19 @@ describe TopicUser do
it 'should be set to tracking if auto_track_topics is enabled' do it 'should be set to tracking if auto_track_topics is enabled' do
user.update_column(:auto_track_topics_after_msecs, 0) user.update_column(:auto_track_topics_after_msecs, 0)
TopicUser.change(user, topic, {starred_at: yesterday}) ensure_topic_user
TopicUser.get(topic, user).notification_level.should == TopicUser.notification_levels[:tracking] TopicUser.get(topic, user).notification_level.should == TopicUser.notification_levels[:tracking]
end end
it 'should reset regular topics to tracking topics if auto track is changed' do it 'should reset regular topics to tracking topics if auto track is changed' do
TopicUser.change(user, topic, {starred_at: yesterday}) ensure_topic_user
user.auto_track_topics_after_msecs = 0 user.auto_track_topics_after_msecs = 0
user.save user.save
topic_user.notification_level.should == TopicUser.notification_levels[:tracking] topic_user.notification_level.should == TopicUser.notification_levels[:tracking]
end end
it 'should be set to "regular" notifications, by default on non creators' do it 'should be set to "regular" notifications, by default on non creators' do
TopicUser.change(user, topic, {starred_at: yesterday}) ensure_topic_user
TopicUser.get(topic,user).notification_level.should == TopicUser.notification_levels[:regular] TopicUser.get(topic,user).notification_level.should == TopicUser.notification_levels[:regular]
end end
@ -195,37 +195,20 @@ describe TopicUser do
describe 'change a flag' do describe 'change a flag' do
it 'creates a forum topic user record' do
user; topic
lambda {
TopicUser.change(user, topic.id, starred: true)
}.should change(TopicUser, :count).by(1)
end
it "only inserts a row once, even on repeated calls" do it "only inserts a row once, even on repeated calls" do
topic; user topic; user
lambda { lambda {
TopicUser.change(user, topic.id, starred: true) TopicUser.change(user, topic.id, total_msecs_viewed: 1)
TopicUser.change(user, topic.id, starred: false) TopicUser.change(user, topic.id, total_msecs_viewed: 2)
TopicUser.change(user, topic.id, starred: true) TopicUser.change(user, topic.id, total_msecs_viewed: 3)
}.should change(TopicUser, :count).by(1) }.should change(TopicUser, :count).by(1)
end end
it 'triggers the observer callbacks when updating' do
UserActionObserver.instance.expects(:after_save).twice
3.times { TopicUser.change(user, topic.id, starred: true) }
end
describe 'after creating a row' do describe 'after creating a row' do
before do before do
TopicUser.change(user, topic.id, starred: true) ensure_topic_user
end
it 'has the correct starred value' do
TopicUser.get(topic, user).should be_starred
end end
it 'has a lookup' do it 'has a lookup' do

View File

@ -257,38 +257,6 @@ describe UserAction do
end end
describe 'synchronize_starred' do
it 'corrects out of sync starred' do
post = Fabricate(:post)
post.topic.toggle_star(post.user, true)
UserAction.delete_all
UserAction.log_action!(
action_type: UserAction::STAR,
user_id: post.user.id,
acting_user_id: post.user.id,
target_topic_id: 99,
target_post_id: -1,
)
UserAction.log_action!(
action_type: UserAction::STAR,
user_id: Fabricate(:user).id,
acting_user_id: post.user.id,
target_topic_id: post.topic_id,
target_post_id: -1,
)
UserAction.synchronize_starred
actions = UserAction.all.to_a
expect(actions.length).to eq(1)
expect(actions.first.action_type).to eq(UserAction::STAR)
expect(actions.first.user_id).to eq(post.user.id)
end
end
describe 'synchronize_target_topic_ids' do describe 'synchronize_target_topic_ids' do
it 'correct target_topic_id' do it 'correct target_topic_id' do
post = Fabricate(:post) post = Fabricate(:post)