work in progress

This commit is contained in:
Sam 2015-05-19 15:45:19 +10:00
commit 43f40c9825
6 changed files with 246 additions and 0 deletions

View File

@ -0,0 +1,5 @@
{{#if topic.accepted_answer}}
<p class="solved">
<i class='fa-check-square fa accepted'></i> Solved by <a data-user-card="{{topic.accepted_answer.username}}">{{topic.accepted_answer.username}}</a> in <a href="{{acceptedAnswerPath}}">post #{{topic.accepted_answer.post_number}}</a>
</p>
{{/if}}

View File

@ -0,0 +1,101 @@
import PostMenuView from 'discourse/views/post-menu';
import PostView from 'discourse/views/post';
import { Button } from 'discourse/views/post-menu';
import Topic from 'discourse/models/topic';
export default {
name: 'extend-for-solved-button',
initialize: function() {
Topic.reopen({
// keeping this here cause there is complex localization
acceptedAnswerHtml: function(){
return I18n.t("")
}.property('accepted_answer')
});
PostView.reopen({
classNameBindings: ['post.accepted_answer:accepted-answer']
});
PostMenuView.registerButton(function(visibleButtons){
if (this.get('post.can_accept_answer')) {
visibleButtons.splice(0,0,new Button('acceptAnswer', 'accepted_answer.accept_answer', 'check-square-o', {className: 'unaccepted'}));
}
if (this.get('post.can_unaccept_answer')) {
visibleButtons.splice(0,0,new Button('unacceptAnswer', 'accepted_answer.unaccept_answer', 'check-square', {className: 'accepted'}));
}
});
PostMenuView.reopen({
acceptedChanged: function(){
this.rerender();
}.observes('post.accepted_answer'),
clickUnacceptAnswer: function(){
this.set('post.can_accept_answer', true);
this.set('post.can_unaccept_answer', false);
this.set('post.topic.has_accepted_answer', false);
Discourse.ajax("/solution/unaccept", {
type: 'POST',
data: {
id: this.get('post.id')
}
}).then(function(){
//
}).catch(function(error){
var message = I18n.t("generic_error");
try {
message = $.parseJSON(error.responseText).errors;
} catch (e) {
// nothing we can do
}
bootbox.alert(message);
});
},
clearAcceptedAnswer: function(){
const posts = this.get('post.topic.postStream.posts');
posts.forEach(function(post){
if (post.get('post_number') > 1 ) {
post.set('accepted_answer',false);
post.set('can_accept_answer',true);
post.set('can_unaccept_answer',false);
}
});
},
clickAcceptAnswer: function(){
this.clearAcceptedAnswer();
this.set('post.can_unaccept_answer', true);
this.set('post.can_accept_answer', false);
this.set('post.accepted_answer', true);
this.set('post.topic.accepted_answer', {
username: this.get('post.username'),
post_number: this.get('post.post_number')
});
Discourse.ajax("/solution/accept", {
type: 'POST',
data: {
id: this.get('post.id')
}
}).then(function(){
//
}).catch(function(error){
var message = I18n.t("generic_error");
try {
message = $.parseJSON(error.responseText).errors;
} catch (e) {
// nothing we can do
}
bootbox.alert(message);
});
}
});
}
};

View File

@ -0,0 +1,15 @@
.post-controls .accepted, .fa.accepted {
color: green;
}
.topic-post.accepted-answer .topic-body {
background-color: #E9FFE0;
}
.cooked .solved {
margin-top: 20px;
margin-bottom: 0px;
padding: 4px 10px;
border: 1px solid #ddd;
background-color: #E9FFE0;
}

View File

@ -0,0 +1,3 @@
en:
site_settings:
categories_with_solved_button: "List of categories where solved button is allowed"

4
config/settings.yml Normal file
View File

@ -0,0 +1,4 @@
uncategorized:
categories_with_solved_button:
default: ''
client: true

118
plugin.rb Normal file
View File

@ -0,0 +1,118 @@
# name: discourse-solved-button
# about: Add a solved button to answers on Discourse
# version: 0.1
# authors: Sam Saffron
PLUGIN_NAME = "discourse_solved_button".freeze
register_asset 'stylesheets/solutions.scss'
after_initialize do
module ::DiscourseSolvedButton
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace DiscourseSolvedButton
end
end
require_dependency "application_controller"
class DiscourseSolvedButton::AnswerController < ::ApplicationController
def accept
post = Post.find(params[:id].to_i)
accepted_id = post.topic.custom_fields["has_accepted_answer"].to_i
if accepted_id
if p2 = Post.find_by(id: accepted_id)
p2.custom_fields["is_accepted_answer"] = nil
p2.save!
end
end
post.custom_fields["is_accepted_answer"] = "true"
post.topic.custom_fields["accepted_answer_post_id"] = post.id
post.topic.save!
post.save!
render json: success_json
end
def unaccept
post = Post.find(params[:id].to_i)
post.custom_fields["is_accepted_answer"] = nil
post.topic.custom_fields["accepted_answer_post_id"] = nil
post.topic.save!
post.save!
render json: success_json
end
end
DiscourseSolvedButton::Engine.routes.draw do
post "/accept" => "answer#accept"
post "/unaccept" => "answer#unaccept"
end
Discourse::Application.routes.append do
mount ::DiscourseSolvedButton::Engine, at: "solution"
end
TopicView.add_post_custom_fields_whitelister do |user|
["is_accepted_answer"]
end
require_dependency 'topic_view_serializer'
class ::TopicViewSerializer
attributes :accepted_answer
def include_accepted_answer?
accepted_answer_post_id
end
def accepted_answer
if info = accepted_answer_post_info
{
post_number: info[0],
username: info[1],
}
end
end
def accepted_answer_post_info
# TODO: we may already have it in the stream ... so bypass query here
Post.where(id: accepted_answer_post_id, topic_id: object.topic.id)
.joins(:user)
.pluck('post_number, username')
.first
end
def accepted_answer_post_id
id = object.topic.custom_fields["accepted_answer_post_id"]
id && id.to_i
end
end
require_dependency 'post_serializer'
class ::PostSerializer
attributes :can_accept_answer, :can_unaccept_answer, :accepted_answer
def can_accept_answer
topic = (topic_view && topic_view.topic) || object.topic
if topic
object.post_number > 1 && !accepted_answer
end
end
def can_unaccept_answer
post_custom_fields["is_accepted_answer"]
end
def accepted_answer
post_custom_fields["is_accepted_answer"]
end
end
end