mirror of
https://github.com/discourse/discourse-solved.git
synced 2025-05-05 07:57:27 +00:00
work in progress
This commit is contained in:
commit
43f40c9825
@ -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}}
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
15
assets/stylesheets/solutions.scss
Normal file
15
assets/stylesheets/solutions.scss
Normal 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;
|
||||||
|
}
|
3
config/locales/server.en.yml
Normal file
3
config/locales/server.en.yml
Normal 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
4
config/settings.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
uncategorized:
|
||||||
|
categories_with_solved_button:
|
||||||
|
default: ''
|
||||||
|
client: true
|
118
plugin.rb
Normal file
118
plugin.rb
Normal 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
|
Loading…
x
Reference in New Issue
Block a user