From 1a989bef07834ad46ea789a0775e406cdcbc4f3f Mon Sep 17 00:00:00 2001 From: Andy Zhao <17884966+Zhao-Andy@users.noreply.github.com> Date: Thu, 26 Mar 2020 14:48:00 -0400 Subject: [PATCH] [deploy] Add response templates to user settings (#6823) * Add response templates controller, routes, and view * Add response templates settings page * Remove dead code * Use proper variable oops * Use proper indentation * Use before action for checking current_user * Remove index action temporarily * Use url helpers for redirects * Use form_with over form_tag and form_for * Persist previous content if edit fails * Use exists for performance * Remove index spec and add CRUD specs * Memoize @response_template * Use workaround for sad paths b/c render doesn't work * Refactor and extract permitted_attributes into var * Use present over exists to preload into memory * Use last over first * Lint for codeclimate * Use two redirects for happy and sad create path * Remove proper index route oops * Codeclimate comma sigh --- app/assets/stylesheets/settings.scss | 40 +++++---- .../response_templates_controller.rb | 64 ++++++++++++++ app/controllers/users_controller.rb | 7 ++ .../response_templates/index.json.jbuilder | 8 ++ app/views/users/_response_templates.html.erb | 39 +++++++++ config/routes.rb | 1 + spec/requests/response_templates_spec.rb | 85 +++++++++++++++++++ 7 files changed, 226 insertions(+), 18 deletions(-) create mode 100644 app/controllers/response_templates_controller.rb create mode 100644 app/views/response_templates/index.json.jbuilder create mode 100644 app/views/users/_response_templates.html.erb create mode 100644 spec/requests/response_templates_spec.rb diff --git a/app/assets/stylesheets/settings.scss b/app/assets/stylesheets/settings.scss index 2d2033087..faaad7da5 100755 --- a/app/assets/stylesheets/settings.scss +++ b/app/assets/stylesheets/settings.scss @@ -529,8 +529,13 @@ $input-width: 650px; } .github-repo-row-name { font-weight: bold; - button { - transition: all 0.6s ease; + form { + display: block; + float: right; + } + button, + a[role='button'] { + transition: all 0.4s ease; cursor: pointer; font-size: 1.2em; font-weight: bold; @@ -545,6 +550,9 @@ $input-width: 650px; &:hover, &:focus { background: $green; + &.danger-button { + background: $red; + } } &:disabled { cursor: wait; @@ -552,23 +560,19 @@ $input-width: 650px; center center; background-size: 75px; } + a { + color: $black; + } + } + &.response-template-row-name { + button, + a[role='button'] { + width: 80px; + margin-left: 2.5px; + margin-right: 2.5px; + text-align: center; + } } - } - .github-repo-fork { - margin-left: 5px; - font-weight: 400; - background: $purple; - color: $bold-blue; - border-radius: 3px; - padding: 1px 6px; - font-size: 0.9em; - } - .github-repo-featured-indicator { - display: inline-block; - float: right; - background: $green; - color: white; - border: 0px; } } } diff --git a/app/controllers/response_templates_controller.rb b/app/controllers/response_templates_controller.rb new file mode 100644 index 000000000..6434c924e --- /dev/null +++ b/app/controllers/response_templates_controller.rb @@ -0,0 +1,64 @@ +class ResponseTemplatesController < ApplicationController + after_action :verify_authorized + + def create + authorize ResponseTemplate + response_template.user_id = current_user.id + response_template.content_type = "body_markdown" + response_template.type_of = "personal_comment" + + if response_template.save + flash[:settings_notice] = "Your response template \"#{response_template.title}\" was created." + redirect_to user_settings_path(tab: "response-templates", id: response_template.id) + else + flash[:error] = "Response template error: #{response_template.errors.full_messages.to_sentence}" + attributes = permitted_attributes(ResponseTemplate) + redirect_to user_settings_path( + tab: "response-templates", + id: response_template.id, + previous_title: attributes[:title], + previous_content: attributes[:content], + ) + end + end + + def destroy + authorize response_template + + if response_template.destroy + flash[:settings_notice] = "Your response template \"#{response_template.title}\" was deleted." + else + flash[:error] = response_template.errors.full_messages.to_sentence # this will probably never fail + end + + redirect_to user_settings_path(tab: "response-templates") + end + + def update + authorize response_template + + attributes = permitted_attributes(ResponseTemplate) + if response_template.update(attributes) + flash[:settings_notice] = "Your response template \"#{response_template.title}\" was updated." + redirect_to user_settings_path(tab: "response-templates", id: response_template.id) + else + flash[:error] = "Response template error: #{response_template.errors.full_messages.to_sentence}" + redirect_to user_settings_path( + tab: "response-templates", + id: response_template.id, + previous_title: attributes[:title], + previous_content: attributes[:content], + ) + end + end + + private + + def response_template + @response_template ||= if params[:id].present? + ResponseTemplate.find(params[:id]) + else + ResponseTemplate.new(permitted_attributes(ResponseTemplate)) + end + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4b9c72e8b..429de8024 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -241,6 +241,8 @@ class UsersController < ApplicationController handle_pro_membership_tab when "account" handle_account_tab + when "response-templates" + handle_response_templates_tab else not_found unless @tab_list.map { |t| t.downcase.tr(" ", "-") }.include? @tab end @@ -307,6 +309,11 @@ class UsersController < ApplicationController HEREDOC end + def handle_response_templates_tab + @response_templates = current_user.response_templates + @response_template = ResponseTemplate.find_or_initialize_by(id: params[:id], user: current_user) + end + def set_user @user = current_user not_found unless @user diff --git a/app/views/response_templates/index.json.jbuilder b/app/views/response_templates/index.json.jbuilder new file mode 100644 index 000000000..6dd11e71f --- /dev/null +++ b/app/views/response_templates/index.json.jbuilder @@ -0,0 +1,8 @@ +json.array!(@response_templates) do |response_template| + json.id response_template.id + json.type_of response_template.type_of + json.user_id response_template.user_id + json.title response_template.title + json.content response_template.content + json.content_truncated truncate(response_template.content, length: 200) +end diff --git a/app/views/users/_response_templates.html.erb b/app/views/users/_response_templates.html.erb new file mode 100644 index 000000000..d38a15e7a --- /dev/null +++ b/app/views/users/_response_templates.html.erb @@ -0,0 +1,39 @@ +

Personal Response Templates

+

Response templates are snippets that you can re-use for quick and accurate comments.

+ +<% if @response_templates.present? %> +

Your templates

+
+
+ <% @response_templates.each do |response_template| %> +
"> +
+ <%= response_template.title %> + <%= form_with path: response_template_path(response_template), method: :delete, onsubmit: "return confirm('Are you sure you want to delete: #{response_template.title}?');" do %> + + <% end %> + EDIT +
+
+ <% end %> +
+
+<% end %> +
+<% if @response_template.persisted? %> + <% title = params[:previous_title] || @response_template.title %> + <% content = params[:previous_content] || @response_template.content %> +

Editing a response template

+ Create a new response template +<% else %> + <% title = params[:previous_title] %> + <% content = params[:previous_content] %> +

Add a new response template

+<% end %> +<%= form_with model: @response_template do |f| %> + <%= f.label :title %> + <%= f.text_field :title, placeholder: "Memorable cue for template", value: title %> + <%= f.label :content, "Comment body (Markdown)" %> + <%= f.text_area :content, value: content %> + <%= f.submit "Submit", class: "cta" %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 881a6abcd..2f9f1991e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -165,6 +165,7 @@ Rails.application.routes.draw do end resources :twitch_live_streams, only: :show, param: :username resources :reactions, only: %i[index create] + resources :response_templates, only: %i[create edit update destroy] resources :feedback_messages, only: %i[index create] resources :organizations, only: %i[update create] resources :followed_articles, only: [:index] diff --git a/spec/requests/response_templates_spec.rb b/spec/requests/response_templates_spec.rb new file mode 100644 index 000000000..73a416f6b --- /dev/null +++ b/spec/requests/response_templates_spec.rb @@ -0,0 +1,85 @@ +require "rails_helper" + +RSpec.describe "ResponseTemplate", type: :request do + let(:user) { create(:user) } + let(:moderator) { create(:user, :tag_moderator) } + let(:admin) { create(:user, :admin) } + + describe "POST /response_templates #create" do + before { sign_in user } + + let(:attributes) do + { + title: "some_title", + content: "some content", + type_of: "personal_comment" + } + end + + it "successfully creates the proper response template" do + post response_templates_path, params: { + response_template: { + title: attributes[:title], + content: attributes[:content] + } + } + + response_template = ResponseTemplate.last + expect(response_template.user_id).to eq user.id + expect(response_template.title).to eq attributes[:title] + expect(response_template.content).to eq attributes[:content] + expect(response_template.type_of).to eq attributes[:type_of] + end + + it "redirects to the edit page upon success" do + post response_templates_path, params: { + response_template: { + title: attributes[:title], + content: attributes[:content] + } + } + expect(response.redirect_url).to include user_settings_path(tab: "response-templates", id: ResponseTemplate.last.id) + end + end + + describe "PATCH /response_templates/:id #update" do + before { sign_in user } + + let(:response_template) { create(:response_template, user: user) } + + it "successfully updates the response template" do + title = "something else" + patch response_template_path(response_template.id), params: { response_template: { title: title } } + expect(ResponseTemplate.first.title).to eq title + end + + it "redirects back to the response template" do + patch response_template_path(response_template.id), params: { response_template: { title: "something else" } } + expect(response.redirect_url).to include user_settings_path(tab: "response-templates", id: ResponseTemplate.first.id) + end + + it "shows the previously written content on a failed submission" do + content = "something something something" + patch response_template_path(response_template.id), params: { response_template: { title: "", content: content } } + follow_redirect! + expect(response.body).to include content + end + end + + describe "DELETE /response_templates/:id #destroy" do + before do + sign_in user + delete response_template_path(response_template.id) + end + + let(:response_template) { create(:response_template, user: user) } + + it "successfully destroys the response template" do + expect(ResponseTemplate.count).to eq 0 + end + + it "redirects to /settings/response_templates" do + expect(response.redirect_url).to include user_settings_path(tab: "response-templates") + end + end +end