Merge pull request #118 from openHPI/rfc-mark-as-answered-extensions

Rfc mark as answered extensions
This commit is contained in:
rteusner
2017-06-12 14:12:36 +02:00
committed by GitHub
13 changed files with 202 additions and 32 deletions

View File

@ -2,4 +2,18 @@
margin-top: 2rem;
height: 600px;
background-color:#f9f9f9
}
}
#thank-you-container {
display: none;
margin-top: 20px;
padding: 5px;
border: solid lightgrey 1px;
background-color: rgba(20, 180, 20, 0.2);
border-radius: 4px;
}
#thank-you-note {
width: 100%;
height: 200px;
}

View File

@ -1,5 +1,5 @@
class RequestForCommentsController < ApplicationController
before_action :set_request_for_comment, only: [:show, :edit, :update, :destroy, :mark_as_solved]
before_action :set_request_for_comment, only: [:show, :edit, :update, :destroy, :mark_as_solved, :set_thank_you_note]
skip_after_action :verify_authorized
@ -34,6 +34,25 @@ class RequestForCommentsController < ApplicationController
end
end
def set_thank_you_note
authorize!
@request_for_comment.thank_you_note = params[:note]
commenters = []
@request_for_comment.comments.distinct.to_a.each {|comment|
commenters.append comment.user
}
commenters = commenters.uniq {|user| user.id}
commenters.each {|commenter| UserMailer.send_thank_you_note(@request_for_comment, commenter).deliver_now}
respond_to do |format|
if @request_for_comment.save
format.json { render :show, status: :ok, location: @request_for_comment }
else
format.json { render json: @request_for_comment.errors, status: :unprocessable_entity }
end
end
end
def submit
end

View File

@ -20,4 +20,12 @@ class UserMailer < ActionMailer::Base
@rfc_link = request_for_comment_url(request_for_comment)
mail(subject: t('mailers.user_mailer.got_new_comment.subject', commenting_user_displayname: @commenting_user_displayname), to: request_for_comment.user.email)
end
def send_thank_you_note(request_for_comments, receiver)
@receiver_displayname = receiver.displayname
@author = request_for_comments.user.displayname
@thank_you_note = request_for_comments.thank_you_note
@rfc_link = request_for_comment_url(request_for_comments)
mail(subject: t('mailers.user_mailer.send_thank_you_note.subject', author: @author), to: receiver.email)
end
end

View File

@ -4,6 +4,8 @@ class RequestForComment < ActiveRecord::Base
belongs_to :exercise
belongs_to :file, class_name: 'CodeOcean::File'
has_many :comments, through: :submission
scope :unsolved, -> { where(solved: [false, nil]) }
def self.last_per_user(n = 5)

View File

@ -8,6 +8,7 @@ class Submission < ActiveRecord::Base
belongs_to :exercise
has_many :testruns
has_many :comments, through: :files
delegate :execution_environment, to: :exercise

View File

@ -24,6 +24,10 @@ class RequestForCommentPolicy < ApplicationPolicy
admin? || author?
end
def set_thank_you_note?
admin? || author?
end
def edit?
admin?
end

View File

@ -1,5 +1,10 @@
<div class="list-group">
<h4 id ="exercise_caption" class="list-group-item-heading" data-exercise-id="<%=@request_for_comment.exercise.id%>" data-comment-exercise-url="<%=create_comment_exercise_request_for_comment_path%>" data-rfc-id = "<%= @request_for_comment.id %>" ><%= link_to(@request_for_comment.exercise.title, [:implement, @request_for_comment.exercise]) %></h4>
<h4 id ="exercise_caption" class="list-group-item-heading" data-exercise-id="<%=@request_for_comment.exercise.id%>" data-comment-exercise-url="<%=create_comment_exercise_request_for_comment_path%>" data-rfc-id = "<%= @request_for_comment.id %>" >
<% if (@request_for_comment.solved?) %>
<span class="fa fa-check" aria-hidden="true"></span>
<% end %>
<%= link_to(@request_for_comment.exercise.title, [:implement, @request_for_comment.exercise]) %>
</h4>
<p class="list-group-item-text">
<%
user = @request_for_comment.user
@ -22,11 +27,21 @@
</h5>
<% if (policy(@request_for_comment).mark_as_solved? and not @request_for_comment.solved?) %>
<button class="btn btn-primary" id="mark-as-solved-button"><%= t('request_for_comments.mark_as_solved') %></button>
<% elsif (@request_for_comment.solved?) %>
<button type="button" class="btn btn-success"><%= t('request_for_comments.solved') %></button>
<% else %>
<button class="btn btn-primary" id="mark-as-solved-button">
<%= t('request_for_comments.mark_as_solved') %>
</button>
<div id="thank-you-container">
<p>
<%= t('request_for_comments.write_a_thank_you_node') %>
</p>
<textarea id="thank-you-note"></textarea>
<button class="btn btn-primary" id="send-thank-you-note">
<%= t('request_for_comments.send_thank_you_note') %>
</button>
<button class="btn btn-default" id="cancel-thank-you-note">
<%= t('request_for_comments.cancel_thank_you_note') %>
</button>
</div>
<% end %>
@ -66,22 +81,46 @@ also, all settings from the rails model needed for the editor configuration in t
var solvedButton = $('#mark-as-solved-button');
var commentOnExerciseButton = $('#comment-exercise-button');
var addCommentExerciseButton = $('#addCommentExerciseButton')
var addCommentExerciseButton = $('#addCommentExerciseButton');
solvedButton.on('click', function(event){
var jqrequest = $.ajax({
var thankYouContainer = $('#thank-you-container');
solvedButton.on('click', function(){
$.ajax({
dataType: 'json',
method: 'GET',
url: location + '/mark_as_solved'
});
jqrequest.done(function(response){
}).done(function(response){
if(response.solved){
solvedButton.hide();
solvedButton.removeClass('btn-primary');
solvedButton.addClass('btn-success');
solvedButton.html('<%= t('request_for_comments.solved') %>');
solvedButton.off('click');
thankYouContainer.show();
}
});
});
$('#send-thank-you-note').on('click', function () {
var value = $('#thank-you-note').val();
if (value) {
$.ajax({
dataType: 'json',
method: 'POST',
url: location + '/set_thank_you_note',
data: {
note: value
}
}).done(function() {
thankYouContainer.hide();
});
}
});
$('#cancel-thank-you-note').on('click', function () {
thankYouContainer.hide();
});
// set file paths for ace
var ACE_FILES_PATH = '/assets/ace/';
_.each(['modePath', 'themePath', 'workerPath'], function(attribute) {
@ -89,7 +128,6 @@ also, all settings from the rails model needed for the editor configuration in t
});
var commentitor = $('.editor');
var userid = commentitor.data('user-id');
commentitor.each(function (index, editor) {
var currentEditor = ace.edit(editor);
@ -203,9 +241,6 @@ also, all settings from the rails model needed for the editor configuration in t
var editor = e.editor;
if (target.className.indexOf("ace_gutter-cell") == -1) return;
//if (!editor.isFocused()) return;
//if (e.clientX > 25 + target.getBoundingClientRect().left) return;
var row = e.getDocumentPosition().row;
e.stop();
@ -250,12 +285,12 @@ also, all settings from the rails model needed for the editor configuration in t
$.flash.danger({
text: message.length > 0 ? message : $('#flash').data('message-failure')
});
};
}
function stringDivider(str, width, spaceReplacer) {
if (str.length>width) {
var p=width
var p=width;
for (;p>0 && str[p]!=' ';p--) {
}
if (p>0) {

View File

@ -0,0 +1 @@
== t('mailers.user_mailer.send_thank_you_note.body', receiver_displayname: @receiver_displayname, link_to_comment: link_to(@rfc_link, @rfc_link), author: @author, thank_you_note: @thank_you_note )

View File

@ -410,6 +410,41 @@ de:
reset_password:
body: 'Bitte besuchen Sie %{link}, sofern Sie Ihr Passwort zurücksetzen wollen.'
subject: Anweisungen zum Zurücksetzen Ihres Passworts
send_thank_you_note:
body: |
English version below <br>
_________________________<br>
<br>
Hallo %{receiver_displayname}, <br>
<br>
%{author} hat Ihnen für Ihren Kommentar auf CodeOcean gedankt. <br>
<br>
%{author} schreibt: %{thank_you_note}<br>
<br>
Sie finden die Kommentaranfrage hier: %{link_to_comment} <br>
<br>
Falls Sie beim Klick auf diesen Link eine Fehlermeldung erhalten, dass Sie nicht berechtigt wären diese Aktion auszuführen, öffnen Sie bitte eine beliebige Programmieraufgabe aus einem Kurs heraus und klicken den Link danach noch einmal.<br>
<br>
Danke, dass Sie anderen Nutzern von CodeOcean helfen!
<br>
Diese Mail wurde automatisch von CodeOcean verschickt.<br>
<br>
_________________________<br>
<br>
Dear %{receiver_displayname}, <br>
<br>
%{author} thanks you for your comment. <br>
<br>
%{author} wrote: %{thank_you_note} <br>
<br>
You can find the request for comments here: %{link_to_comment} <br>
<br>
If you receive an error that you are not authorized to perform this action when clicking the link, please log-in through any course exercise beforehand and click the link again. <br>
<br>
Thank you for helping other users on CodeOcean!
<br>
This mail was automatically sent by CodeOcean. <br>
subject: "%{author} sagt danke!"
request_for_comments:
click_here: Zum Kommentieren auf die Seitenleiste klicken!
comments: Kommentare
@ -428,6 +463,9 @@ de:
show_unsolved: "Nur ungelöste Anfragen anzeigen"
solved: "Diese Frage wurde erfolgreich beantwortet"
comment_exercise: "Ich möchte die Aufgabenstellung kommentieren"
write_a_thank_you_node: "Wenn Sie möchten, können Sie sich bei allen Mitstudenten, die Ihnen bei der Beantwortung Ihrer Frage geholfen haben, bedanken:"
send_thank_you_note: "Senden"
cancel_thank_you_note: "Nichts senden"
sessions:
create:
failure: Fehlerhafte E-Mail oder Passwort.

View File

@ -431,6 +431,41 @@ en:
reset_password:
body: 'Please visit %{link} if you want to reset your password.'
subject: Password reset instructions
send_thank_you_note:
body: |
English version below <br>
_________________________<br>
<br>
Hallo %{receiver_displayname}, <br>
<br>
%{author} hat Ihnen für Ihren Kommentar auf CodeOcean gedankt. <br>
<br>
%{author} schreibt: %{thank_you_note}<br>
<br>
Sie finden die Kommentaranfrage hier: %{link_to_comment} <br>
<br>
Falls Sie beim Klick auf diesen Link eine Fehlermeldung erhalten, dass Sie nicht berechtigt wären diese Aktion auszuführen, öffnen Sie bitte eine beliebige Programmieraufgabe aus einem Kurs heraus und klicken den Link danach noch einmal.<br>
<br>
Danke, dass Sie anderen Nutzern von CodeOcean helfen!
<br>
Diese Mail wurde automatisch von CodeOcean verschickt.<br>
<br>
_________________________<br>
<br>
Dear %{receiver_displayname}, <br>
<br>
%{author} thanks you for your comment. <br>
<br>
%{author} wrote: %{thank_you_note} <br>
<br>
You can find the request for comments here: %{link_to_comment} <br>
<br>
If you receive an error that you are not authorized to perform this action when clicking the link, please log-in through any course exercise beforehand and click the link again. <br>
<br>
Thank you for helping other users on CodeOcean!
<br>
This mail was automatically sent by CodeOcean. <br>
subject: "%{author} says thank you!"
request_for_comments:
click_here: Click on this sidebar to comment!
comments: Comments
@ -449,6 +484,9 @@ en:
show_unsolved: "Unvsolved requests"
solved: "This question has been answered"
comment_exercise: "I would like to give feedback for this exercise"
write_a_thank_you_node: "If you want, you can write a thank you note to all your commenters:"
send_thank_you_note: "Send"
cancel_thank_you_note: "Don't send"
sessions:
create:
failure: Invalid email or password.

View File

@ -11,6 +11,7 @@ Rails.application.routes.draw do
member do
get :mark_as_solved
post :create_comment_exercise
post :set_thank_you_note
end
end
resources :comments, except: [:destroy] do

View File

@ -0,0 +1,5 @@
class AddThankYouNoteToRequestForComments < ActiveRecord::Migration
def change
add_column :request_for_comments, :thank_you_note, :text
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170403162848) do
ActiveRecord::Schema.define(version: 20170608141612) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -93,7 +93,7 @@ ActiveRecord::Schema.define(version: 20170403162848) do
create_table "exercise_tags", force: :cascade do |t|
t.integer "exercise_id"
t.integer "tag_id"
t.integer "factor", default: 0
t.integer "factor", default: 1
end
create_table "exercises", force: :cascade do |t|
@ -110,7 +110,7 @@ ActiveRecord::Schema.define(version: 20170403162848) do
t.boolean "hide_file_tree"
t.boolean "allow_file_creation"
t.boolean "allow_auto_completion", default: false
t.integer "expected_worktime_seconds", default: 0
t.integer "expected_worktime_seconds", default: 60
t.integer "expected_difficulty", default: 1
end
@ -247,15 +247,16 @@ ActiveRecord::Schema.define(version: 20170403162848) do
end
create_table "request_for_comments", force: :cascade do |t|
t.integer "user_id", null: false
t.integer "exercise_id", null: false
t.integer "file_id", null: false
t.integer "user_id", null: false
t.integer "exercise_id", null: false
t.integer "file_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "user_type", limit: 255
t.string "user_type", limit: 255
t.text "question"
t.boolean "solved", default: false
t.boolean "solved", default: false
t.integer "submission_id"
t.text "thank_you_note"
end
create_table "searches", force: :cascade do |t|
@ -296,12 +297,13 @@ ActiveRecord::Schema.define(version: 20170403162848) do
end
create_table "user_exercise_feedbacks", force: :cascade do |t|
t.integer "exercise_id", null: false
t.integer "user_id", null: false
t.string "user_type", null: false
t.integer "exercise_id", null: false
t.integer "user_id", null: false
t.string "user_type", null: false
t.integer "difficulty"
t.integer "working_time_seconds"
t.string "feedback_text"
t.integer "user_estimated_worktime"
end
create_table "user_exercise_interventions", force: :cascade do |t|
@ -309,6 +311,8 @@ ActiveRecord::Schema.define(version: 20170403162848) do
t.string "user_type"
t.integer "exercise_id"
t.integer "intervention_id"
t.integer "accumulated_worktime_s"
t.text "reason"
t.datetime "created_at"
t.datetime "updated_at"
end