mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Added method for testing ember stuff
Collapse user actions in UI so it stops looking crazy Removed dud dupe user action TOPIC_RESPONSE Always show the owner of a post on the user page, actions by others at the bottom
This commit is contained in:
@@ -220,7 +220,6 @@ window.Discourse = Ember.Application.createWithMixins
|
|||||||
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus)
|
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus)
|
||||||
Discourse.insertProbes()
|
Discourse.insertProbes()
|
||||||
|
|
||||||
|
|
||||||
# subscribe to any site customizations that are loaded
|
# subscribe to any site customizations that are loaded
|
||||||
$('link.custom-css').each ->
|
$('link.custom-css').each ->
|
||||||
split = @href.split("/")
|
split = @href.split("/")
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
RESPONSE = "6"
|
|
||||||
MENTION = "7"
|
|
||||||
TOPIC_RESPONSE = "8"
|
|
||||||
QUOTE = "9"
|
|
||||||
NEW_PRIVATE_MESSAGE = "12"
|
|
||||||
GOT_PRIVATE_MESSAGE = "13"
|
|
||||||
|
|
||||||
window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
||||||
|
|
||||||
avatarLarge: (->
|
avatarLarge: (->
|
||||||
@@ -68,7 +61,7 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
|||||||
callback(message)
|
callback(message)
|
||||||
|
|
||||||
filterStream: (filter)->
|
filterStream: (filter)->
|
||||||
filter = Discourse.User.statGroups[filter].join(",") if Discourse.User.statGroups[filter]
|
filter = Discourse.UserAction.statGroups[filter].join(",") if Discourse.UserAction.statGroups[filter]
|
||||||
@set('streamFilter', filter)
|
@set('streamFilter', filter)
|
||||||
@set('stream', Em.A())
|
@set('stream', Em.A())
|
||||||
@loadMoreUserActions()
|
@loadMoreUserActions()
|
||||||
@@ -97,6 +90,7 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
|||||||
if result and result.user_actions and result.user_actions.each
|
if result and result.user_actions and result.user_actions.each
|
||||||
result.user_actions.each (i)=>
|
result.user_actions.each (i)=>
|
||||||
stream.pushObject(Discourse.UserAction.create(i))
|
stream.pushObject(Discourse.UserAction.create(i))
|
||||||
|
stream = Discourse.UserAction.collapseStream(stream)
|
||||||
@set('stream', stream)
|
@set('stream', stream)
|
||||||
callback() if callback
|
callback() if callback
|
||||||
|
|
||||||
@@ -104,7 +98,7 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
|||||||
total=0
|
total=0
|
||||||
return 0 unless stats = @get('stats')
|
return 0 unless stats = @get('stats')
|
||||||
@get('stats').each (s)->
|
@get('stats').each (s)->
|
||||||
total+= parseInt(s.count) unless s.action_type is NEW_PRIVATE_MESSAGE || s.action_type is GOT_PRIVATE_MESSAGE
|
total+= parseInt(s.count) unless s.get("isPM")
|
||||||
total
|
total
|
||||||
).property('stats.@each')
|
).property('stats.@each')
|
||||||
|
|
||||||
@@ -112,7 +106,7 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
|||||||
r = []
|
r = []
|
||||||
return r if @blank('stats')
|
return r if @blank('stats')
|
||||||
@get('stats').each (s)->
|
@get('stats').each (s)->
|
||||||
r.push s unless (s.action_type == NEW_PRIVATE_MESSAGE || s.action_type == GOT_PRIVATE_MESSAGE)
|
r.push s unless s.get('isPM')
|
||||||
r
|
r
|
||||||
).property('stats.@each')
|
).property('stats.@each')
|
||||||
|
|
||||||
@@ -120,14 +114,14 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
|||||||
r = []
|
r = []
|
||||||
return r if @blank('stats')
|
return r if @blank('stats')
|
||||||
@get('stats').each (s)->
|
@get('stats').each (s)->
|
||||||
r.push s if (s.action_type is NEW_PRIVATE_MESSAGE or s.action_type is GOT_PRIVATE_MESSAGE)
|
r.push s if s.get('isPM')
|
||||||
r
|
r
|
||||||
).property('stats.@each')
|
).property('stats.@each')
|
||||||
|
|
||||||
inboxCount: (->
|
inboxCount: (->
|
||||||
r = 0
|
r = 0
|
||||||
@get('stats').each (s)->
|
@get('stats').each (s)->
|
||||||
if s.action_type is GOT_PRIVATE_MESSAGE
|
if s.action_type == Discourse.UserAction.GOT_PRIVATE_MESSAGE
|
||||||
r = s.count
|
r = s.count
|
||||||
return false
|
return false
|
||||||
return r
|
return r
|
||||||
@@ -136,7 +130,7 @@ window.Discourse.User = Discourse.Model.extend Discourse.Presence,
|
|||||||
sentItemsCount: (->
|
sentItemsCount: (->
|
||||||
r = 0
|
r = 0
|
||||||
@get('stats').each (s)->
|
@get('stats').each (s)->
|
||||||
if s.action_type is NEW_PRIVATE_MESSAGE
|
if s.action_type == Discourse.UserAction.NEW_PRIVATE_MESSAGE
|
||||||
r = s.count
|
r = s.count
|
||||||
return false
|
return false
|
||||||
return r
|
return r
|
||||||
@@ -155,10 +149,13 @@ window.Discourse.User.reopenClass
|
|||||||
g = {}
|
g = {}
|
||||||
stats.each (s) =>
|
stats.each (s) =>
|
||||||
found = false
|
found = false
|
||||||
for k,v of @statGroups
|
for k,v of Discourse.UserAction.statGroups
|
||||||
if v.contains(s.action_type)
|
if v.contains(s.action_type)
|
||||||
found = true
|
found = true
|
||||||
g[k] = {count: 0} unless g[k]
|
g[k] = Em.Object.create(
|
||||||
|
description: Em.String.i18n("user_action_descriptions.#{k}")
|
||||||
|
count: 0
|
||||||
|
action_type: parseInt(k,10)) unless g[k]
|
||||||
g[k].count += parseInt(s.count)
|
g[k].count += parseInt(s.count)
|
||||||
c = g[k].count
|
c = g[k].count
|
||||||
if s.action_type == k
|
if s.action_type == k
|
||||||
@@ -172,24 +169,26 @@ window.Discourse.User.reopenClass
|
|||||||
).exclude (s)->
|
).exclude (s)->
|
||||||
!s
|
!s
|
||||||
|
|
||||||
statGroups: (->
|
|
||||||
g = {}
|
|
||||||
g[RESPONSE] = [RESPONSE,MENTION,TOPIC_RESPONSE,QUOTE]
|
|
||||||
g
|
|
||||||
)()
|
|
||||||
|
|
||||||
find: (username) ->
|
find: (username) ->
|
||||||
promise = new RSVP.Promise()
|
promise = new RSVP.Promise()
|
||||||
$.ajax
|
$.ajax
|
||||||
url: "/users/" + username + '.json',
|
url: "/users/" + username + '.json',
|
||||||
success: (json) =>
|
success: (json) =>
|
||||||
json.user.stats = @groupStats(json.user.stats)
|
# todo: decompose to object
|
||||||
json.user.stream = json.user.stream.map (ua) -> Discourse.UserAction.create(ua) if json.user.stream
|
json.user.stats = @groupStats(json.user.stats.map (s)->
|
||||||
|
obj = Em.Object.create(s)
|
||||||
|
obj.isPM = obj.action_type == Discourse.UserAction.NEW_PRIVATE_MESSAGE ||
|
||||||
|
obj.action_type == Discourse.UserAction.GOT_PRIVATE_MESSAGE
|
||||||
|
obj
|
||||||
|
)
|
||||||
|
json.user.stream = Discourse.UserAction.collapseStream(json.user.stream.map (ua) ->
|
||||||
|
Discourse.UserAction.create(ua)) if json.user.stream
|
||||||
user = Discourse.User.create(json.user)
|
user = Discourse.User.create(json.user)
|
||||||
promise.resolve(user)
|
promise.resolve(user)
|
||||||
error: (xhr) -> promise.reject(xhr)
|
error: (xhr) -> promise.reject(xhr)
|
||||||
promise
|
promise
|
||||||
|
|
||||||
|
|
||||||
createAccount: (name, email, password, username, passwordConfirm, challenge) ->
|
createAccount: (name, email, password, username, passwordConfirm, challenge) ->
|
||||||
$.ajax
|
$.ajax
|
||||||
url: '/users'
|
url: '/users'
|
||||||
|
|||||||
@@ -2,3 +2,104 @@ window.Discourse.UserAction = Discourse.Model.extend
|
|||||||
postUrl:(->
|
postUrl:(->
|
||||||
Discourse.Utilities.postUrl(@get('slug'), @get('topic_id'), @get('post_number'))
|
Discourse.Utilities.postUrl(@get('slug'), @get('topic_id'), @get('post_number'))
|
||||||
).property()
|
).property()
|
||||||
|
|
||||||
|
isPM: (->
|
||||||
|
a = @get('action_type')
|
||||||
|
a == UserAction.NEW_PRIVATE_MESSAGE || UserAction.GOT_PRIVATE_MESSAGE
|
||||||
|
).property()
|
||||||
|
|
||||||
|
addChild: (action)->
|
||||||
|
groups = @get("childGroups")
|
||||||
|
unless groups
|
||||||
|
groups =
|
||||||
|
likes: Discourse.UserActionGroup.create(icon: "icon-heart")
|
||||||
|
stars: Discourse.UserActionGroup.create(icon: "icon-star")
|
||||||
|
edits: Discourse.UserActionGroup.create(icon: "icon-pencil")
|
||||||
|
bookmarks: Discourse.UserActionGroup.create(icon: "icon-bookmark")
|
||||||
|
|
||||||
|
@set("childGroups", groups)
|
||||||
|
|
||||||
|
ua = Discourse.UserAction
|
||||||
|
bucket = switch action.action_type
|
||||||
|
when ua.LIKE,ua.WAS_LIKED then "likes"
|
||||||
|
when ua.STAR then "stars"
|
||||||
|
when ua.EDIT then "edits"
|
||||||
|
when ua.BOOKMARK then "bookmarks"
|
||||||
|
|
||||||
|
current = groups[bucket]
|
||||||
|
current.push(action) if current
|
||||||
|
return
|
||||||
|
|
||||||
|
children:(->
|
||||||
|
g = @get("childGroups")
|
||||||
|
rval = []
|
||||||
|
if g
|
||||||
|
rval = [g.likes, g.stars, g.edits, g.bookmarks].filter((i) -> i.get("items") && i.get("items").length > 0)
|
||||||
|
rval
|
||||||
|
).property("childGroups")
|
||||||
|
|
||||||
|
switchToActing: ->
|
||||||
|
@set('username', @get('acting_username'))
|
||||||
|
@set('avatar_template', @get('acting_avatar_template'))
|
||||||
|
@set('name', @get('acting_name'))
|
||||||
|
|
||||||
|
window.Discourse.UserAction.reopenClass
|
||||||
|
collapseStream: (stream) ->
|
||||||
|
collapse = [@LIKE, @WAS_LIKED, @STAR, @EDIT, @BOOKMARK]
|
||||||
|
uniq = {}
|
||||||
|
collapsed = Em.A()
|
||||||
|
pos = 0
|
||||||
|
stream.each (item)->
|
||||||
|
key = "#{item.topic_id}-#{item.post_number}"
|
||||||
|
|
||||||
|
found = uniq[key]
|
||||||
|
|
||||||
|
if found == undefined
|
||||||
|
if collapse.indexOf(item.action_type) >= 0
|
||||||
|
current = Discourse.UserAction.create(item)
|
||||||
|
current.set('action_type',null)
|
||||||
|
current.set('description',null)
|
||||||
|
item.switchToActing()
|
||||||
|
current.addChild(item)
|
||||||
|
else
|
||||||
|
current = item
|
||||||
|
uniq[key] = pos
|
||||||
|
collapsed[pos] = current
|
||||||
|
pos += 1
|
||||||
|
else
|
||||||
|
if collapse.indexOf(item.action_type) >= 0
|
||||||
|
item.switchToActing()
|
||||||
|
collapsed[found].addChild(item)
|
||||||
|
else
|
||||||
|
collapsed[found].set('action_type', item.get('action_type'))
|
||||||
|
collapsed[found].set('description', item.get('description'))
|
||||||
|
|
||||||
|
|
||||||
|
collapsed
|
||||||
|
|
||||||
|
|
||||||
|
# in future we should be sending this through from the server
|
||||||
|
LIKE: 1
|
||||||
|
WAS_LIKED: 2
|
||||||
|
BOOKMARK: 3
|
||||||
|
NEW_TOPIC: 4
|
||||||
|
POST: 5
|
||||||
|
RESPONSE: 6
|
||||||
|
MENTION: 7
|
||||||
|
QUOTE: 9
|
||||||
|
STAR: 10
|
||||||
|
EDIT: 11
|
||||||
|
NEW_PRIVATE_MESSAGE: 12
|
||||||
|
GOT_PRIVATE_MESSAGE: 13
|
||||||
|
|
||||||
|
window.Discourse.UserAction.reopenClass
|
||||||
|
statGroups: (->
|
||||||
|
g = {}
|
||||||
|
g[Discourse.UserAction.RESPONSE] = [
|
||||||
|
Discourse.UserAction.RESPONSE,
|
||||||
|
Discourse.UserAction.MENTION,
|
||||||
|
Discourse.UserAction.QUOTE
|
||||||
|
]
|
||||||
|
g
|
||||||
|
)()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
window.Discourse.UserActionGroup = Discourse.Model.extend
|
||||||
|
push: (item)->
|
||||||
|
@items = [] unless @items
|
||||||
|
@items.push(item)
|
||||||
@@ -12,6 +12,14 @@
|
|||||||
<p class='excerpt'>
|
<p class='excerpt'>
|
||||||
{{{unbound excerpt}}}
|
{{{unbound excerpt}}}
|
||||||
</p>
|
</p>
|
||||||
|
{{#each children}}
|
||||||
|
<div class='child-actions'>
|
||||||
|
<i class="icon {{unbound icon}}"></i>
|
||||||
|
{{#each items}}
|
||||||
|
<a href="/users/{{unbound username}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="tiny" extraClasses="actor" avatarTemplatePath="avatar_template" ignoreTitle="true"}}</div></a>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
{{/with}}
|
{{/with}}
|
||||||
{{/collection}}
|
{{/collection}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -268,6 +268,27 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// styling of bottom section
|
||||||
|
#user-stream .child-actions {
|
||||||
|
margin-top: 8px;
|
||||||
|
.avatar-link {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
width: 15px;
|
||||||
|
display: inline-block;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
.avatar-wrapper {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.avatar-link {
|
||||||
|
margin-right: 3px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@include medium-width {
|
@include medium-width {
|
||||||
#user-stream {
|
#user-stream {
|
||||||
width: 725px;
|
width: 725px;
|
||||||
@@ -277,4 +298,4 @@
|
|||||||
#user-stream {
|
#user-stream {
|
||||||
width: 680px;
|
width: 680px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ class PostAlertObserver < ActiveRecord::Observer
|
|||||||
exclude_user_ids << extract_mentioned_users(post).map{|u| u.id}
|
exclude_user_ids << extract_mentioned_users(post).map{|u| u.id}
|
||||||
exclude_user_ids << extract_quoted_users(post).map{|u| u.id}
|
exclude_user_ids << extract_quoted_users(post).map{|u| u.id}
|
||||||
exclude_user_ids.flatten!
|
exclude_user_ids.flatten!
|
||||||
|
|
||||||
TopicUser.where(topic_id: post.topic_id, notification_level: TopicUser::NotificationLevel::WATCHING).includes(:user).each do |tu|
|
TopicUser.where(topic_id: post.topic_id, notification_level: TopicUser::NotificationLevel::WATCHING).includes(:user).each do |tu|
|
||||||
create_notification(tu.user, Notification.Types[:posted], post) unless exclude_user_ids.include?(tu.user_id)
|
create_notification(tu.user, Notification.Types[:posted], post) unless exclude_user_ids.include?(tu.user_id)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class TopicUser < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.auto_track(user_id, topic_id, reason)
|
def self.auto_track(user_id, topic_id, reason)
|
||||||
if exec_sql("select 1 from topic_users where user_id = ? and topic_id = ? and notifications_reason_id is null", user_id, topic_id).count == 1
|
if TopicUser.where(user_id: user_id, topic_id: topic_id, notifications_reason_id: nil).exists?
|
||||||
self.change(user_id, topic_id,
|
self.change(user_id, topic_id,
|
||||||
notification_level: NotificationLevel::TRACKING,
|
notification_level: NotificationLevel::TRACKING,
|
||||||
notifications_reason_id: reason
|
notifications_reason_id: reason
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ require_dependency 'sql_builder'
|
|||||||
|
|
||||||
class UserAction < ActiveRecord::Base
|
class UserAction < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
belongs_to :target_post, :class_name => "Post"
|
||||||
attr_accessible :acting_user_id, :action_type, :target_topic_id, :target_post_id, :target_user_id, :user_id
|
attr_accessible :acting_user_id, :action_type, :target_topic_id, :target_post_id, :target_user_id, :user_id
|
||||||
|
|
||||||
validates_presence_of :action_type
|
validates_presence_of :action_type
|
||||||
@@ -15,7 +16,6 @@ class UserAction < ActiveRecord::Base
|
|||||||
POST = 5
|
POST = 5
|
||||||
RESPONSE= 6
|
RESPONSE= 6
|
||||||
MENTION = 7
|
MENTION = 7
|
||||||
TOPIC_RESPONSE = 8
|
|
||||||
QUOTE = 9
|
QUOTE = 9
|
||||||
STAR = 10
|
STAR = 10
|
||||||
EDIT = 11
|
EDIT = 11
|
||||||
@@ -29,7 +29,6 @@ class UserAction < ActiveRecord::Base
|
|||||||
NEW_TOPIC,
|
NEW_TOPIC,
|
||||||
POST,
|
POST,
|
||||||
RESPONSE,
|
RESPONSE,
|
||||||
TOPIC_RESPONSE,
|
|
||||||
LIKE,
|
LIKE,
|
||||||
WAS_LIKED,
|
WAS_LIKED,
|
||||||
MENTION,
|
MENTION,
|
||||||
@@ -39,23 +38,19 @@ class UserAction < ActiveRecord::Base
|
|||||||
].each_with_index.to_a.flatten]
|
].each_with_index.to_a.flatten]
|
||||||
|
|
||||||
def self.stats(user_id, guardian)
|
def self.stats(user_id, guardian)
|
||||||
sql = <<SQL
|
results = UserAction.select("action_type, COUNT(*) count, '' description")
|
||||||
select action_type, count(*) count
|
.where(user_id: user_id)
|
||||||
from user_actions
|
.group('action_type')
|
||||||
where user_id = ?
|
.to_a
|
||||||
group by action_type
|
|
||||||
SQL
|
|
||||||
|
|
||||||
results = self.exec_sql(sql, user_id).to_a
|
|
||||||
|
|
||||||
# should push this into the sql at some point, but its simple enough for now
|
# should push this into the sql at some point, but its simple enough for now
|
||||||
unless guardian.can_see_private_messages?(user_id)
|
unless guardian.can_see_private_messages?(user_id)
|
||||||
results.reject!{|a| [GOT_PRIVATE_MESSAGE, NEW_PRIVATE_MESSAGE].include?(a["action_type"].to_i)}
|
results.reject!{|a| [GOT_PRIVATE_MESSAGE, NEW_PRIVATE_MESSAGE].include?(a.action_type)}
|
||||||
end
|
end
|
||||||
|
|
||||||
results.sort!{|a,b| ORDER[a["action_type"].to_i] <=> ORDER[b["action_type"].to_i]}
|
results.sort!{|a,b| ORDER[a.action_type] <=> ORDER[b.action_type]}
|
||||||
results.each do |row|
|
results.each do |row|
|
||||||
row["description"] = self.description(row["action_type"], detailed: true)
|
row.description = self.description(row.action_type, detailed: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
results
|
results
|
||||||
@@ -74,14 +69,22 @@ SQL
|
|||||||
guardian = opts[:guardian]
|
guardian = opts[:guardian]
|
||||||
ignore_private_messages = opts[:ignore_private_messages]
|
ignore_private_messages = opts[:ignore_private_messages]
|
||||||
|
|
||||||
|
# The weird thing is that target_post_id can be null, so it makes everything
|
||||||
|
# ever so more complex. Should we allow this, not sure.
|
||||||
|
|
||||||
builder = SqlBuilder.new("
|
builder = SqlBuilder.new("
|
||||||
select t.title, a.action_type, a.created_at,
|
SELECT
|
||||||
t.id topic_id, coalesce(p.post_number, 1) post_number, u.email ,u.username, u.name, u.id user_id, coalesce(p.cooked, p2.cooked) cooked
|
t.title, a.action_type, a.created_at, t.id topic_id,
|
||||||
from user_actions as a
|
coalesce(p.post_number, 1) post_number,
|
||||||
join topics t on t.id = a.target_topic_id
|
pu.email ,pu.username, pu.name, pu.id user_id,
|
||||||
left join posts p on p.id = a.target_post_id
|
u.email acting_email, u.username acting_username, u.name acting_name, u.id acting_user_id,
|
||||||
left join users u on u.id = a.acting_user_id
|
coalesce(p.cooked, p2.cooked) cooked
|
||||||
left join posts p2 on p2.topic_id = a.target_topic_id and p2.post_number = 1
|
FROM user_actions as a
|
||||||
|
JOIN topics t on t.id = a.target_topic_id
|
||||||
|
LEFT JOIN posts p on p.id = a.target_post_id
|
||||||
|
JOIN posts p2 on p2.topic_id = a.target_topic_id and p2.post_number = 1
|
||||||
|
JOIN users u on u.id = a.acting_user_id
|
||||||
|
JOIN users pu on pu.id = COALESCE(p.user_id, t.user_id)
|
||||||
/*where*/
|
/*where*/
|
||||||
/*order_by*/
|
/*order_by*/
|
||||||
/*offset*/
|
/*offset*/
|
||||||
@@ -109,13 +112,16 @@ left join posts p2 on p2.topic_id = a.target_topic_id and p2.post_number = 1
|
|||||||
end
|
end
|
||||||
|
|
||||||
data.each do |row|
|
data.each do |row|
|
||||||
|
row["action_type"] = row["action_type"].to_i
|
||||||
row["description"] = self.description(row["action_type"])
|
row["description"] = self.description(row["action_type"])
|
||||||
row["created_at"] = DateTime.parse(row["created_at"])
|
row["created_at"] = DateTime.parse(row["created_at"])
|
||||||
# we should probably cache the excerpts in the db at some point
|
# we should probably cache the excerpts in the db at some point
|
||||||
row["excerpt"] = PrettyText.excerpt(row["cooked"],300) if row["cooked"]
|
row["excerpt"] = PrettyText.excerpt(row["cooked"],300) if row["cooked"]
|
||||||
row["cooked"] = nil
|
row["cooked"] = nil
|
||||||
row["avatar_template"] = User.avatar_template(row["email"])
|
row["avatar_template"] = User.avatar_template(row["email"])
|
||||||
|
row["acting_avatar_template"] = User.avatar_template(row["acting_email"])
|
||||||
row.delete("email")
|
row.delete("email")
|
||||||
|
row.delete("acting_email")
|
||||||
row["slug"] = Slug.for(row["title"])
|
row["slug"] = Slug.for(row["title"])
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -137,8 +143,6 @@ left join posts p2 on p2.topic_id = a.target_topic_id and p2.post_number = 1
|
|||||||
t[:likes_given]
|
t[:likes_given]
|
||||||
when RESPONSE
|
when RESPONSE
|
||||||
t[:responses]
|
t[:responses]
|
||||||
when TOPIC_RESPONSE
|
|
||||||
t[:topic_responses]
|
|
||||||
when POST
|
when POST
|
||||||
t[:posts]
|
t[:posts]
|
||||||
when MENTION
|
when MENTION
|
||||||
@@ -161,7 +165,7 @@ left join posts p2 on p2.topic_id = a.target_topic_id and p2.post_number = 1
|
|||||||
then t[:posted]
|
then t[:posted]
|
||||||
when LIKE,WAS_LIKED
|
when LIKE,WAS_LIKED
|
||||||
then t[:liked]
|
then t[:liked]
|
||||||
when RESPONSE, TOPIC_RESPONSE,POST
|
when RESPONSE,POST
|
||||||
then t[:responded_to]
|
then t[:responded_to]
|
||||||
when BOOKMARK
|
when BOOKMARK
|
||||||
then t[:bookmarked]
|
then t[:bookmarked]
|
||||||
|
|||||||
@@ -110,21 +110,6 @@ class UserActionObserver < ActiveRecord::Observer
|
|||||||
UserAction.remove_action!(row)
|
UserAction.remove_action!(row)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return if model.topic.private_message?
|
|
||||||
|
|
||||||
# a bit odd but we may have stray records
|
|
||||||
if model.topic and model.topic.user_id != model.user_id
|
|
||||||
row[:action_type] = UserAction::TOPIC_RESPONSE
|
|
||||||
row[:user_id] = model.topic.user_id
|
|
||||||
|
|
||||||
if model.deleted_at.nil?
|
|
||||||
UserAction.log_action!(row)
|
|
||||||
else
|
|
||||||
UserAction.remove_action!(row)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_topic(model)
|
def log_topic(model)
|
||||||
|
|||||||
@@ -460,6 +460,8 @@ en:
|
|||||||
saving: "Saving..."
|
saving: "Saving..."
|
||||||
saved: "Saved!"
|
saved: "Saved!"
|
||||||
|
|
||||||
|
user_action_descriptions:
|
||||||
|
"6": "Responses"
|
||||||
user:
|
user:
|
||||||
information: "User Information"
|
information: "User Information"
|
||||||
profile: Profile
|
profile: Profile
|
||||||
|
|||||||
14
db/migrate/20130213021450_remove_topic_response_actions.rb
Normal file
14
db/migrate/20130213021450_remove_topic_response_actions.rb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
class RemoveTopicResponseActions < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
# 2 notes:
|
||||||
|
# migrations should never use the object model to run sql, otherwise they are a time bomb
|
||||||
|
# this action type is not valid, we log a "response" action type anyway due to the watch implementation, its a relic.
|
||||||
|
#
|
||||||
|
# There is an open question about we should keep stuff in the user stream on the user page, even if a topic is unwatched
|
||||||
|
# Eg: I am not watching a topic I created, when somebody responds to the topic should I be notified on the user page?
|
||||||
|
execute 'delete from user_actions where action_type = 8'
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
end
|
||||||
|
end
|
||||||
2072
db/structure.sql
2072
db/structure.sql
File diff suppressed because it is too large
Load Diff
21
spec/javascripts/hacks.js
Normal file
21
spec/javascripts/hacks.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// hacks for ember, this sets up our app for testing
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
var currentWindowOnload = window.onload;
|
||||||
|
window.onload = function() {
|
||||||
|
if (currentWindowOnload) {
|
||||||
|
currentWindowOnload();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('<div id="main"><div class="rootElement"></div></div>').appendTo($('body')).hide();
|
||||||
|
|
||||||
|
Discourse.SiteSettings = {}
|
||||||
|
|
||||||
|
Discourse.Router.map(function() {
|
||||||
|
this.route("jasmine",{path: "/jasmine"});
|
||||||
|
Discourse.routeBuilder.apply(this)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})()
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
describe "Discourse.MessageBus", ->
|
describe "Discourse.MessageBus", ->
|
||||||
|
|
||||||
describe "Web Sockets", ->
|
describe "Long polling", ->
|
||||||
|
|
||||||
bus = Discourse.MessageBus
|
bus = Discourse.MessageBus
|
||||||
bus.start()
|
bus.start()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe "PreloadStore", ->
|
|||||||
expect(PreloadStore.contains('joker')).toBe(false)
|
expect(PreloadStore.contains('joker')).toBe(false)
|
||||||
|
|
||||||
it "returns true for a stored key", ->
|
it "returns true for a stored key", ->
|
||||||
expect(PreloadStore.contains('bane')).toBe(true)
|
expect(PreloadStore.contains('bane')).toBe(true)
|
||||||
|
|
||||||
describe 'getStatic', ->
|
describe 'getStatic', ->
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ describe "PreloadStore", ->
|
|||||||
expect(PreloadStore.getStatic('joker')).toBe(undefined)
|
expect(PreloadStore.getStatic('joker')).toBe(undefined)
|
||||||
|
|
||||||
it "returns the the key if it exists", ->
|
it "returns the the key if it exists", ->
|
||||||
expect(PreloadStore.getStatic('bane')).toBe('evil')
|
expect(PreloadStore.getStatic('bane')).toBe('evil')
|
||||||
|
|
||||||
it "removes the key after being called", ->
|
it "removes the key after being called", ->
|
||||||
PreloadStore.getStatic('bane')
|
PreloadStore.getStatic('bane')
|
||||||
|
|||||||
@@ -1,11 +1,46 @@
|
|||||||
//= require env
|
//= require env
|
||||||
//= require jquery
|
|
||||||
|
|
||||||
//= require external/jquery.ui.widget.js
|
//= require ../../app/assets/javascripts/preload_store.js
|
||||||
//= require external/handlebars-1.0.rc.2.js
|
|
||||||
|
|
||||||
//= require preload_store
|
// probe framework first
|
||||||
|
//= require ../../app/assets/javascripts/discourse/components/probes.js
|
||||||
|
|
||||||
|
// Externals we need to load first
|
||||||
|
//= require ../../app/assets/javascripts/external/jquery-1.8.2.js
|
||||||
|
|
||||||
|
//= require ../../app/assets/javascripts/external/jquery.ui.widget.js
|
||||||
|
//= require ../../app/assets/javascripts/external/handlebars-1.0.rc.2.js
|
||||||
|
//= require ../../app/assets/javascripts/external/ember.js
|
||||||
|
|
||||||
|
// Pagedown customizations
|
||||||
|
//= require ../../app/assets/javascripts/pagedown_custom.js
|
||||||
|
|
||||||
|
// The rest of the externals
|
||||||
//= require_tree ../../app/assets/javascripts/external
|
//= require_tree ../../app/assets/javascripts/external
|
||||||
|
//= require i18n
|
||||||
|
//= require ../../app/assets/javascripts/discourse/translations
|
||||||
|
|
||||||
|
//= require ../../app/assets/javascripts/discourse/helpers/i18n_helpers
|
||||||
|
//= require ../../app/assets/javascripts/discourse
|
||||||
|
|
||||||
|
// Stuff we need to load first
|
||||||
|
//= require_tree ../../app/assets/javascripts/discourse/mixins
|
||||||
|
//= require ../../app/assets/javascripts/discourse/components/debounce
|
||||||
|
//= require ../../app/assets/javascripts/discourse/views/view
|
||||||
|
//= require ../../app/assets/javascripts/discourse/controllers/controller
|
||||||
|
//= require ../../app/assets/javascripts/discourse/views/modal/modal_body_view
|
||||||
|
//= require ../../app/assets/javascripts/discourse/models/model
|
||||||
|
//= require ../../app/assets/javascripts/discourse/routes/discourse_route
|
||||||
|
|
||||||
|
//= require_tree ../../app/assets/javascripts/discourse/controllers
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/components
|
//= require_tree ../../app/assets/javascripts/discourse/components
|
||||||
|
//= require_tree ../../app/assets/javascripts/discourse/models
|
||||||
|
//= require_tree ../../app/assets/javascripts/discourse/views
|
||||||
|
//= require_tree ../../app/assets/javascripts/discourse/helpers
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/templates
|
//= require_tree ../../app/assets/javascripts/discourse/templates
|
||||||
|
//= require_tree ../../app/assets/javascripts/discourse/routes
|
||||||
|
|
||||||
|
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
|
|
||||||
|
//= require hacks
|
||||||
|
|||||||
16
spec/javascripts/user_action_spec.js.coffee
Normal file
16
spec/javascripts/user_action_spec.js.coffee
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
describe "Discourse.UserAction", ->
|
||||||
|
|
||||||
|
describe "collapseStream", ->
|
||||||
|
it "collapses all likes", ->
|
||||||
|
actions = [
|
||||||
|
Discourse.UserAction.create(action_type: Discourse.UserAction.LIKE, topic_id:1, user_id:1, post_number:1)
|
||||||
|
Discourse.UserAction.create(action_type: Discourse.UserAction.EDIT, topic_id:2, user_id:1, post_number:1)
|
||||||
|
Discourse.UserAction.create(action_type: Discourse.UserAction.LIKE, topic_id:1, user_id:2, post_number:1)
|
||||||
|
]
|
||||||
|
|
||||||
|
actions = Discourse.UserAction.collapseStream(actions)
|
||||||
|
expect(actions.length).toBe(2)
|
||||||
|
|
||||||
|
expect(actions[0].get("children").length).toBe(1)
|
||||||
|
expect(actions[0].get("children")[0].items.length).toBe(2)
|
||||||
|
|
||||||
@@ -111,7 +111,6 @@ describe UserAction do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
it 'should not log a post user action' do
|
it 'should not log a post user action' do
|
||||||
@post.user.user_actions.where(action_type: UserAction::POST).first.should be_nil
|
@post.user.user_actions.where(action_type: UserAction::POST).first.should be_nil
|
||||||
end
|
end
|
||||||
@@ -121,7 +120,7 @@ describe UserAction do
|
|||||||
before do
|
before do
|
||||||
@other_user = Fabricate(:coding_horror)
|
@other_user = Fabricate(:coding_horror)
|
||||||
@mentioned = Fabricate(:admin)
|
@mentioned = Fabricate(:admin)
|
||||||
@response = Fabricate(:post, topic: @post.topic, user: @other_user, raw: "perhaps @#{@mentioned.username} knows how this works?")
|
@response = Fabricate(:post, reply_to_post_number: 1, topic: @post.topic, user: @other_user, raw: "perhaps @#{@mentioned.username} knows how this works?")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should log a post action for the poster' do
|
it 'should log a post action for the poster' do
|
||||||
@@ -129,7 +128,7 @@ describe UserAction do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'should log a post action for the original poster' do
|
it 'should log a post action for the original poster' do
|
||||||
@post.user.user_actions.where(action_type: UserAction::TOPIC_RESPONSE).first.should_not be_nil
|
@post.user.user_actions.where(action_type: UserAction::RESPONSE).first.should_not be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should log a mention for the mentioned' do
|
it 'should log a mention for the mentioned' do
|
||||||
@@ -142,6 +141,10 @@ describe UserAction do
|
|||||||
@response.user.user_actions.where(action_type: UserAction::POST).count.should == 1
|
@response.user.user_actions.where(action_type: UserAction::POST).count.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'should not log topic reply and reply for a single post' do
|
||||||
|
@post.user.user_actions.joins(:target_post).where('posts.post_number = 2').count.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user