Skip to content

Commit 7d9a84b

Browse files
committed
New User Education goes through a server side ComposerMessages check. Composer message for users
who don't have avatars.
1 parent 32163bc commit 7d9a84b

16 files changed

Lines changed: 356 additions & 109 deletions

app/assets/javascripts/discourse/controllers/composer_controller.js

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Discourse.ComposerController = Discourse.Controller.extend({
1010
needs: ['modal', 'topic', 'composerMessages'],
1111

1212
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY),
13-
13+
checkedMessages: false,
1414

1515
init: function() {
1616
this._super();
@@ -117,33 +117,18 @@ Discourse.ComposerController = Discourse.Controller.extend({
117117
});
118118
},
119119

120-
_considerNewUserEducation: function() {
121-
122-
// We don't show education when editing a post.
123-
if (this.get('model.editingPost')) return;
124-
125-
// If creating a topic, use topic_count, otherwise post_count
126-
var count = this.get('model.creatingTopic') ? Discourse.User.currentProp('topic_count') : Discourse.User.currentProp('reply_count');
127-
if (count >= Discourse.SiteSettings.educate_until_posts) { return; }
128-
129-
// The user must have typed a reply
130-
if (!this.get('typedReply')) return;
131-
132-
// If visible update the text
133-
var educationKey = this.get('model.creatingTopic') ? 'new-topic' : 'new-reply',
134-
messageController = this.get('controllers.composerMessages');
135-
136-
Discourse.ajax("/education/" + educationKey, {dataType: 'html'}).then(function(result) {
137-
messageController.popup({
138-
templateName: 'composer/education',
139-
body: result
140-
});
141-
});
142-
143-
}.observes('typedReply', 'model.creatingTopic', 'currentUser.reply_count'),
120+
/**
121+
Checks to see if a reply has been typed. This is signaled by a keyUp
122+
event in a view.
144123
124+
@method checkReplyLength
125+
**/
145126
checkReplyLength: function() {
146-
this.set('typedReply', this.present('model.reply'));
127+
if (this.present('model.reply')) {
128+
// Notify the composer messages controller that a reply has been typed. Some
129+
// messages only appear after typing.
130+
this.get('controllers.composerMessages').typedReply()
131+
}
147132
},
148133

149134
/**
@@ -171,11 +156,11 @@ Discourse.ComposerController = Discourse.Controller.extend({
171156
similarTopics.clear();
172157
similarTopics.pushObjects(newTopics);
173158

174-
messageController.popup({
159+
messageController.popup(Discourse.ComposerMessage.create({
175160
templateName: 'composer/similar_topics',
176161
similarTopics: similarTopics,
177162
extraClass: 'similar-topics'
178-
});
163+
}));
179164
});
180165

181166
},
@@ -203,7 +188,6 @@ Discourse.ComposerController = Discourse.Controller.extend({
203188

204189
var promise = opts.promise || Ember.Deferred.create();
205190
opts.promise = promise;
206-
this.set('typedReply', false);
207191

208192
if (!opts.draftKey) {
209193
alert("composer was opened without a draft key");
@@ -272,8 +256,10 @@ Discourse.ComposerController = Discourse.Controller.extend({
272256

273257
composer = composer || Discourse.Composer.create();
274258
composer.open(opts);
259+
275260
this.set('model', composer);
276261
composer.set('composeState', Discourse.Composer.OPEN);
262+
composerMessages.queryFor(this.get('model'));
277263
promise.resolve();
278264
return promise;
279265
},

app/assets/javascripts/discourse/controllers/composer_messages_controller.js

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,92 @@
99
Discourse.ComposerMessagesController = Ember.ArrayController.extend({
1010
needs: ['composer'],
1111

12+
// Whether we've checked our messages
13+
checkedMessages: false,
14+
15+
/**
16+
Initialize the controller
17+
**/
1218
init: function() {
1319
this._super();
14-
this.set('messagesByTemplate', {});
20+
this.reset();
1521
},
1622

23+
/**
24+
Displays a new message
25+
26+
@method popup
27+
@params {Object} msg The message to display
28+
**/
1729
popup: function(msg) {
1830
var messagesByTemplate = this.get('messagesByTemplate'),
19-
existing = messagesByTemplate[msg.templateName];
31+
templateName = msg.get('templateName'),
32+
existing = messagesByTemplate[templateName];
2033

2134
if (!existing) {
2235
this.pushObject(msg);
23-
messagesByTemplate[msg.templateName] = msg;
36+
messagesByTemplate[templateName] = msg;
2437
}
2538
},
2639

40+
/**
41+
Closes and hides a message.
42+
43+
@method closeMessage
44+
@params {Object} message The message to dismiss
45+
**/
2746
closeMessage: function(message) {
2847
this.removeObject(message);
2948
},
3049

50+
/**
51+
Resets all active messages. For example if composing a new post.
52+
53+
@method reset
54+
**/
3155
reset: function() {
3256
this.clear();
3357
this.set('messagesByTemplate', {});
58+
this.set('queuedForTyping', new Em.Set());
59+
this.set('checkedMessages', false);
60+
},
61+
62+
/**
63+
Called after the user has typed a reply. Some messages only get shown after being
64+
typed.
65+
66+
@method typedReply
67+
**/
68+
typedReply: function() {
69+
var self = this;
70+
this.get('queuedForTyping').forEach(function (msg) {
71+
self.popup(msg);
72+
})
73+
},
74+
75+
/**
76+
Figure out if there are any messages that should be displayed above the composer.
77+
78+
@method queryFor
79+
@params {Discourse.Composer} composer The composer model
80+
**/
81+
queryFor: function(composer) {
82+
if (this.get('checkedMessages')) { return; }
83+
84+
var self = this,
85+
queuedForTyping = self.get('queuedForTyping');
86+
87+
Discourse.ComposerMessage.find(composer).then(function (messages) {
88+
self.set('checkedMessages', true);
89+
messages.forEach(function (msg) {
90+
console.log(msg);
91+
if (msg.wait_for_typing) {
92+
queuedForTyping.addObject(msg);
93+
} else {
94+
self.popup(msg);
95+
}
96+
});
97+
});
3498
}
3599

36100
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
Represents a pop up message displayed over the composer
3+
4+
@class ComposerMessage
5+
@extends Ember.Object
6+
@namespace Discourse
7+
@module Discourse
8+
**/
9+
Discourse.ComposerMessage = Em.Object.extend({});
10+
11+
Discourse.ComposerMessage.reopenClass({
12+
/**
13+
Look for composer messages given the current composing settings.
14+
15+
@method find
16+
@param {Discourse.Composer} composer The current composer
17+
@returns {Discourse.ComposerMessage} the composer message to display (or null)
18+
**/
19+
find: function(composer) {
20+
21+
var data = { composerAction: composer.get('action') },
22+
topicId = composer.get('topic.id'),
23+
postId = composer.get('post.id');
24+
25+
if (topicId) { data.topic_id = topicId };
26+
if (postId) { data.post_id = postId };
27+
28+
return Discourse.ajax('/composer-messages', { data: data }).then(function (messages) {
29+
return messages.map(function (message) {
30+
return Discourse.ComposerMessage.create(message);
31+
});
32+
});
33+
}
34+
35+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require_dependency 'composer_messages_finder'
2+
3+
class ComposerMessagesController < ApplicationController
4+
5+
before_filter :ensure_logged_in
6+
7+
def index
8+
finder = ComposerMessagesFinder.new(current_user, params.slice(:composerAction, :topic_id, :post_id))
9+
render_json_dump([finder.find].compact)
10+
end
11+
12+
end
13+

app/controllers/education_controller.rb

Lines changed: 0 additions & 25 deletions
This file was deleted.

app/controllers/posts_controller.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,6 @@ def replies
177177
render_serialized(post.replies, PostSerializer)
178178
end
179179

180-
# Returns the "you're creating a post education"
181-
def education_text
182-
183-
end
184-
185180
def bookmark
186181
post = find_post_from_params
187182
if current_user
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module ComposerMessagesHelper
2+
end

app/models/user.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ def temporary_key
160160
key
161161
end
162162

163+
def created_topic_count
164+
topics.count
165+
end
163166

164167
# tricky, we need our bus to be subscribed from the right spot
165168
def sync_notification_channel_position
@@ -502,6 +505,7 @@ def topic_create_allowed_category_ids
502505
Category.topic_create_allowed(self.id).select(:id)
503506
end
504507

508+
505509
# Flag all posts from a user as spam
506510
def flag_linked_posts_as_spam
507511
admin = Discourse.system_user

app/models/user_history.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ def self.with_filters(filters)
4646
query
4747
end
4848

49+
def self.exists_for_user?(user, action_type)
50+
self.where(target_user_id: user.id, action: UserHistory.actions[action_type]).exists?
51+
end
52+
4953
def new_value_is_json?
5054
[UserHistory.actions[:change_site_customization], UserHistory.actions[:delete_site_customization]].include?(action)
5155
end

config/locales/server.en.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ en:
104104
105105
For more guidance, [see our FAQ](/faq). This panel will only appear for your first %{education_posts_text}.
106106
107+
avatar: |
108+
### How about a new picture for your account?
109+
110+
You've posted a few topics and replies, but your avatar isn't as unique as you are -- it's the same default avatar all new users have.
111+
112+
Have you considered **[visiting your user profile](%{profile_path})** and uploading a custom image that represents you?
113+
114+
It's easier to follow community discussions and find interesting people in conversations when everyone has a unique avatar!
115+
107116
108117
activerecord:
109118
attributes:

0 commit comments

Comments
 (0)