From 8a632a09cd09310318d181b29c5b2f25013c4f29 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 20:12:22 +0100 Subject: [PATCH 01/15] Create Announcement model & controller --- app/assets/javascripts/announcement.coffee | 3 +++ app/assets/stylesheets/announcement.scss | 3 +++ app/controllers/announcement_controller.rb | 20 +++++++++++++++++++ app/helpers/announcement_helper.rb | 2 ++ app/models/announcement.rb | 2 ++ app/views/announcement/edit.html.haml | 2 ++ app/views/announcement/index.html.haml | 8 ++++++++ app/views/announcement/new.html.haml | 2 ++ config/routes.rb | 7 +++++++ .../20200419183714_create_announcements.rb | 14 +++++++++++++ db/schema.rb | 14 ++++++++++++- spec/helpers/announcement_helper_spec.rb | 15 ++++++++++++++ spec/models/announcement_spec.rb | 5 +++++ 13 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/announcement.coffee create mode 100644 app/assets/stylesheets/announcement.scss create mode 100644 app/controllers/announcement_controller.rb create mode 100644 app/helpers/announcement_helper.rb create mode 100644 app/models/announcement.rb create mode 100644 app/views/announcement/edit.html.haml create mode 100644 app/views/announcement/index.html.haml create mode 100644 app/views/announcement/new.html.haml create mode 100644 db/migrate/20200419183714_create_announcements.rb create mode 100644 spec/helpers/announcement_helper_spec.rb create mode 100644 spec/models/announcement_spec.rb diff --git a/app/assets/javascripts/announcement.coffee b/app/assets/javascripts/announcement.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/announcement.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/announcement.scss b/app/assets/stylesheets/announcement.scss new file mode 100644 index 00000000..e922d541 --- /dev/null +++ b/app/assets/stylesheets/announcement.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the announcement controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/announcement_controller.rb b/app/controllers/announcement_controller.rb new file mode 100644 index 00000000..1d52ff1e --- /dev/null +++ b/app/controllers/announcement_controller.rb @@ -0,0 +1,20 @@ +class AnnouncementController < ApplicationController + def index + @announcements = Announcement.all + end + + def new + end + + def create + end + + def edit + end + + def update + end + + def destroy + end +end diff --git a/app/helpers/announcement_helper.rb b/app/helpers/announcement_helper.rb new file mode 100644 index 00000000..b71ddc14 --- /dev/null +++ b/app/helpers/announcement_helper.rb @@ -0,0 +1,2 @@ +module AnnouncementHelper +end diff --git a/app/models/announcement.rb b/app/models/announcement.rb new file mode 100644 index 00000000..aa98a0e5 --- /dev/null +++ b/app/models/announcement.rb @@ -0,0 +1,2 @@ +class Announcement < ApplicationRecord +end diff --git a/app/views/announcement/edit.html.haml b/app/views/announcement/edit.html.haml new file mode 100644 index 00000000..26015ad5 --- /dev/null +++ b/app/views/announcement/edit.html.haml @@ -0,0 +1,2 @@ +

Announcement#edit

+

Find me in app/views/announcement/edit.html.erb

diff --git a/app/views/announcement/index.html.haml b/app/views/announcement/index.html.haml new file mode 100644 index 00000000..b7a759d4 --- /dev/null +++ b/app/views/announcement/index.html.haml @@ -0,0 +1,8 @@ +- provide(:title, generate_title("Announcements")) +.container.j2-page + .row + .col-md-12 + = link_to "Add new", :announcement_new, class: "btn btn-default" + - @announcements.each do |announcement| + .panel.panel-default + = announcement.content diff --git a/app/views/announcement/new.html.haml b/app/views/announcement/new.html.haml new file mode 100644 index 00000000..a14230c1 --- /dev/null +++ b/app/views/announcement/new.html.haml @@ -0,0 +1,2 @@ +

Announcement#new

+

Find me in app/views/announcement/new.html.erb

diff --git a/config/routes.rb b/config/routes.rb index 8176f058..bdc9a8c7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -127,5 +127,12 @@ Rails.application.routes.draw do match '/:username/groups(/p/:page)', to: 'user#groups', via: 'get', as: :show_user_groups, defaults: {page: 1} match '/:username/questions(/p/:page)', to: 'user#questions', via: 'get', as: :show_user_questions, defaults: {page: 1} + match "/admin/announcements", to: "announcement#index", via: :get, as: :announcement_index + match "/admin/announcements", to: "announcement#create", via: :post, as: :announcement_create + match "/admin/announcements/new", to: "announcement#new", via: :get, as: :announcement_new + match "/admin/announcements/:id/edit", to: "announcement#edit", via: :get, as: :announcement_edit + match "/admin/announcements/:id", to: "announcement#update", via: :patch, as: :announcement_update + match "/admin/announcements/:id", to: "announcement#destroy", via: :delete, as: :announcement_destroy + puts 'processing time of routes.rb: ' + "#{(Time.now - start).round(3).to_s.ljust(5, '0')}s".light_green end diff --git a/db/migrate/20200419183714_create_announcements.rb b/db/migrate/20200419183714_create_announcements.rb new file mode 100644 index 00000000..1aedd713 --- /dev/null +++ b/db/migrate/20200419183714_create_announcements.rb @@ -0,0 +1,14 @@ +class CreateAnnouncements < ActiveRecord::Migration[5.2] + def change + create_table :announcements do |t| + t.text :content, null: false + t.string :link_text + t.string :link_href + t.datetime :starts_at, null: false + t.datetime :ends_at, null: false + t.belongs_to :user, null: false + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 439625e6..215202c3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,11 +10,23 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2016_01_05_165913) do +ActiveRecord::Schema.define(version: 2020_04_19_183714) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "announcements", force: :cascade do |t| + t.text "content", null: false + t.string "link_text" + t.string "link_href" + t.datetime "starts_at", null: false + t.datetime "ends_at", null: false + t.bigint "user_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["user_id"], name: "index_announcements_on_user_id" + end + create_table "answers", id: :serial, force: :cascade do |t| t.text "content" t.integer "question_id" diff --git a/spec/helpers/announcement_helper_spec.rb b/spec/helpers/announcement_helper_spec.rb new file mode 100644 index 00000000..04b6d9e2 --- /dev/null +++ b/spec/helpers/announcement_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the AnnouncementHelper. For example: +# +# describe AnnouncementHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe AnnouncementHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/announcement_spec.rb b/spec/models/announcement_spec.rb new file mode 100644 index 00000000..0bfc218b --- /dev/null +++ b/spec/models/announcement_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Announcement, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From e3b89f734626484e8d2552517e8c51f6b2c26fca Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 20:34:48 +0100 Subject: [PATCH 02/15] Implement creation of announcements --- app/controllers/announcement_controller.rb | 15 +++++++++++++++ app/models/announcement.rb | 1 + app/views/announcement/new.html.haml | 21 +++++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/controllers/announcement_controller.rb b/app/controllers/announcement_controller.rb index 1d52ff1e..4ab15b7a 100644 --- a/app/controllers/announcement_controller.rb +++ b/app/controllers/announcement_controller.rb @@ -4,9 +4,18 @@ class AnnouncementController < ApplicationController end def new + @announcement = Announcement.new end def create + @announcement = Announcement.new(announcement_params) + @announcement.user = current_user + if @announcement.save + flash[:success] = "Announcement created successfully." + redirect_to action: :index + else + render 'announcement/new' + end end def edit @@ -17,4 +26,10 @@ class AnnouncementController < ApplicationController def destroy end + + private + + def announcement_params + params.require(:announcement).permit(:content, :link_text, :link_href, :starts_at, :ends_at) + end end diff --git a/app/models/announcement.rb b/app/models/announcement.rb index aa98a0e5..03010a0c 100644 --- a/app/models/announcement.rb +++ b/app/models/announcement.rb @@ -1,2 +1,3 @@ class Announcement < ApplicationRecord + belongs_to :user end diff --git a/app/views/announcement/new.html.haml b/app/views/announcement/new.html.haml index a14230c1..d41b08f1 100644 --- a/app/views/announcement/new.html.haml +++ b/app/views/announcement/new.html.haml @@ -1,2 +1,19 @@ -

Announcement#new

-

Find me in app/views/announcement/new.html.erb

+- provide(:title, generate_title("Add new announcement")) +.container.j2-page + = bootstrap_form_for(@announcement, url: {action: "create"}) do |f| + .row + .col-md-12 + = f.text_area :content, label: "Content" + .row + .col-md-6 + = f.url_field :link_href, label: "Link URL" + .col-md-6 + = f.datetime_field :link_text, label: "Link text" + .row + .col-md-6 + = f.datetime_field :starts_at, label: "Start time" + .col-md-6 + = f.datetime_field :ends_at, label: "End time" + .row + .col-md-12.text-right + = f.submit class: "btn btn-primary" From f14a168bcef2fd815fec7c6c7ea0afcc6e8a62fc Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 20:50:33 +0100 Subject: [PATCH 03/15] Implement deletion of announcements --- app/controllers/announcement_controller.rb | 7 +++++++ app/views/announcement/index.html.haml | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/controllers/announcement_controller.rb b/app/controllers/announcement_controller.rb index 4ab15b7a..f7219a4b 100644 --- a/app/controllers/announcement_controller.rb +++ b/app/controllers/announcement_controller.rb @@ -19,12 +19,19 @@ class AnnouncementController < ApplicationController end def edit + @announcement = Announcement.find(params[:id]) end def update end def destroy + if Announcement.destroy(params[:id]) + flash[:success] = "Announcement deleted successfully." + else + flash[:error] = "Failed to delete announcement." + end + redirect_to announcement_index_path end private diff --git a/app/views/announcement/index.html.haml b/app/views/announcement/index.html.haml index b7a759d4..a82a9066 100644 --- a/app/views/announcement/index.html.haml +++ b/app/views/announcement/index.html.haml @@ -5,4 +5,10 @@ = link_to "Add new", :announcement_new, class: "btn btn-default" - @announcements.each do |announcement| .panel.panel-default - = announcement.content + .panel-heading + = announcement.starts_at + .panel-body + = announcement.content + .panel-footer + = button_to "Edit", announcement_edit_path(id: announcement.id), class: 'btn btn-link' + = button_to "Delete", announcement_destroy_path(id: announcement.id), method: :delete, class: 'btn btn-link', confirm: 'Are you sure you want to delete this announcement?' \ No newline at end of file From 6187cb0b6c8b3a410f7c3fa122c31abeec225f2f Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 20:58:57 +0100 Subject: [PATCH 04/15] Add the ability to edit announcements --- app/controllers/announcement_controller.rb | 6 ++++++ app/views/announcement/edit.html.haml | 21 +++++++++++++++++++-- app/views/announcement/index.html.haml | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/controllers/announcement_controller.rb b/app/controllers/announcement_controller.rb index f7219a4b..7c4a9b0a 100644 --- a/app/controllers/announcement_controller.rb +++ b/app/controllers/announcement_controller.rb @@ -23,6 +23,12 @@ class AnnouncementController < ApplicationController end def update + if Announcement.update(params[:id], announcement_params) + flash[:success] = "Announcement updated successfully." + redirect_to announcement_index_path + else + render 'announcement/edit' + end end def destroy diff --git a/app/views/announcement/edit.html.haml b/app/views/announcement/edit.html.haml index 26015ad5..387ff707 100644 --- a/app/views/announcement/edit.html.haml +++ b/app/views/announcement/edit.html.haml @@ -1,2 +1,19 @@ -

Announcement#edit

-

Find me in app/views/announcement/edit.html.erb

+- provide(:title, generate_title("Edit announcement")) +.container.j2-page + = bootstrap_form_for(@announcement, url: {action: "update"}, method: "PATCH") do |f| + .row + .col-md-12 + = f.text_area :content, label: "Content" + .row + .col-md-6 + = f.url_field :link_href, label: "Link URL" + .col-md-6 + = f.datetime_field :link_text, label: "Link text" + .row + .col-md-6 + = f.datetime_field :starts_at, label: "Start time" + .col-md-6 + = f.datetime_field :ends_at, label: "End time" + .row + .col-md-12.text-right + = f.submit class: "btn btn-primary" diff --git a/app/views/announcement/index.html.haml b/app/views/announcement/index.html.haml index a82a9066..0d117c83 100644 --- a/app/views/announcement/index.html.haml +++ b/app/views/announcement/index.html.haml @@ -10,5 +10,5 @@ .panel-body = announcement.content .panel-footer - = button_to "Edit", announcement_edit_path(id: announcement.id), class: 'btn btn-link' + = button_to "Edit", announcement_edit_path(id: announcement.id), method: :get, class: 'btn btn-link' = button_to "Delete", announcement_destroy_path(id: announcement.id), method: :delete, class: 'btn btn-link', confirm: 'Are you sure you want to delete this announcement?' \ No newline at end of file From 2ecc746e235d91168b56984ef16755e7e54eb738 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 21:11:22 +0100 Subject: [PATCH 05/15] Implement validation for announcements --- app/models/announcement.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/models/announcement.rb b/app/models/announcement.rb index 03010a0c..f2a7684f 100644 --- a/app/models/announcement.rb +++ b/app/models/announcement.rb @@ -1,3 +1,18 @@ class Announcement < ApplicationRecord belongs_to :user + + validates :content, presence: true + validates :starts_at, presence: true + validates :link_href, presence: true, if: -> { link_text.present? } + validate :starts_at, :validate_date_range + + def link_present? + link_text.present? + end + + def validate_date_range + if starts_at > ends_at + errors.add(:starts_at, "Start date must be before end date") + end + end end From 473f2cdcc52d81328fa5fc94608ec01dde2417b9 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 21:26:55 +0100 Subject: [PATCH 06/15] Show announcement validation errors on the frontend --- app/controllers/announcement_controller.rb | 4 +++- app/views/announcement/edit.html.haml | 10 ++++++++++ app/views/announcement/new.html.haml | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app/controllers/announcement_controller.rb b/app/controllers/announcement_controller.rb index 7c4a9b0a..93083c1e 100644 --- a/app/controllers/announcement_controller.rb +++ b/app/controllers/announcement_controller.rb @@ -23,7 +23,9 @@ class AnnouncementController < ApplicationController end def update - if Announcement.update(params[:id], announcement_params) + @announcement = Announcement.find(params[:id]) + @announcement.update(announcement_params) + if @announcement.save flash[:success] = "Announcement updated successfully." redirect_to announcement_index_path else diff --git a/app/views/announcement/edit.html.haml b/app/views/announcement/edit.html.haml index 387ff707..ee7eb3ba 100644 --- a/app/views/announcement/edit.html.haml +++ b/app/views/announcement/edit.html.haml @@ -1,6 +1,16 @@ - provide(:title, generate_title("Edit announcement")) .container.j2-page = bootstrap_form_for(@announcement, url: {action: "update"}, method: "PATCH") do |f| + - if @announcement.errors.any? + .row + .col-md-12 + .alert.alert-danger + %strong + = pluralize(@announcement.errors.count, "error") + prohibited this announcement from being saved: + %ul + - @announcement.errors.full_messages.each do |err| + %li= err .row .col-md-12 = f.text_area :content, label: "Content" diff --git a/app/views/announcement/new.html.haml b/app/views/announcement/new.html.haml index d41b08f1..57ed3eaf 100644 --- a/app/views/announcement/new.html.haml +++ b/app/views/announcement/new.html.haml @@ -1,6 +1,16 @@ - provide(:title, generate_title("Add new announcement")) .container.j2-page = bootstrap_form_for(@announcement, url: {action: "create"}) do |f| + - if @announcement.errors.any? + .row + .col-md-12 + .alert.alert-danger + %strong + = pluralize(@announcement.errors.count, "error") + prohibited this announcement from being saved: + %ul + - @announcement.errors.full_messages.each do |err| + %li= err .row .col-md-12 = f.text_area :content, label: "Content" From b6d6c1fded439aae8ef69b993516debaeb5ec12c Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 21:38:21 +0100 Subject: [PATCH 07/15] Add announcements to the top of the application template --- app/controllers/application_controller.rb | 5 +++++ app/models/announcement.rb | 10 ++++++++++ app/views/layouts/application.html.haml | 1 + app/views/shared/_announcements.haml | 6 ++++++ 4 files changed, 22 insertions(+) create mode 100644 app/views/shared/_announcements.haml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ccc1e3f9..e5c9919b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -6,6 +6,7 @@ class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? before_action :check_locale before_action :banned? + before_action :find_active_announcements # check if user wants to read def check_locale @@ -50,6 +51,10 @@ class ApplicationController < ActionController::Base end end + def find_active_announcements + @active_announcements ||= Announcement.find_active + end + include ApplicationHelper protected diff --git a/app/models/announcement.rb b/app/models/announcement.rb index f2a7684f..3014a117 100644 --- a/app/models/announcement.rb +++ b/app/models/announcement.rb @@ -6,6 +6,16 @@ class Announcement < ApplicationRecord validates :link_href, presence: true, if: -> { link_text.present? } validate :starts_at, :validate_date_range + def self.find_active + Rails.cache.fetch "announcement_active", expires_in: 1.minute do + where "starts_at <= :now AND ends_at > :now", now: Time.current + end + end + + def active? + Time.now.utc >= starts_at && Time.now.utc < ends_at + end + def link_present? link_text.present? end diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 12f5e08b..d40a87d8 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -25,6 +25,7 @@ = csrf_meta_tags %body#version1 = render 'layouts/header' + = render 'shared/announcements' = yield = render 'shared/locales' - if Rails.env.development? diff --git a/app/views/shared/_announcements.haml b/app/views/shared/_announcements.haml new file mode 100644 index 00000000..6885694d --- /dev/null +++ b/app/views/shared/_announcements.haml @@ -0,0 +1,6 @@ +.container.announcements + - @active_announcements.each do |announcement| + .alert.alert-announcement + %p= announcement.content + - if announcement.link_present? + %a.alert-link{ href: announcement.link_href }= announcement.link_text From a505e7ee71abb01995b88d646f4fc2e5a7c195bb Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 21:45:07 +0100 Subject: [PATCH 08/15] Ensure we're logged in as an admin when using the AnnouncementController --- app/controllers/announcement_controller.rb | 2 ++ config/routes.rb | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/controllers/announcement_controller.rb b/app/controllers/announcement_controller.rb index 93083c1e..ee2bbb24 100644 --- a/app/controllers/announcement_controller.rb +++ b/app/controllers/announcement_controller.rb @@ -1,4 +1,6 @@ class AnnouncementController < ApplicationController + before_action :authenticate_user! + def index @announcements = Announcement.all end diff --git a/config/routes.rb b/config/routes.rb index bdc9a8c7..56dfd2b4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -127,12 +127,15 @@ Rails.application.routes.draw do match '/:username/groups(/p/:page)', to: 'user#groups', via: 'get', as: :show_user_groups, defaults: {page: 1} match '/:username/questions(/p/:page)', to: 'user#questions', via: 'get', as: :show_user_questions, defaults: {page: 1} - match "/admin/announcements", to: "announcement#index", via: :get, as: :announcement_index - match "/admin/announcements", to: "announcement#create", via: :post, as: :announcement_create - match "/admin/announcements/new", to: "announcement#new", via: :get, as: :announcement_new - match "/admin/announcements/:id/edit", to: "announcement#edit", via: :get, as: :announcement_edit - match "/admin/announcements/:id", to: "announcement#update", via: :patch, as: :announcement_update - match "/admin/announcements/:id", to: "announcement#destroy", via: :delete, as: :announcement_destroy + constraints ->(req) { req.env['warden'].authenticate?(scope: :user) && + (req.env['warden'].user.admin?) } do + match "/admin/announcements", to: "announcement#index", via: :get, as: :announcement_index + match "/admin/announcements", to: "announcement#create", via: :post, as: :announcement_create + match "/admin/announcements/new", to: "announcement#new", via: :get, as: :announcement_new + match "/admin/announcements/:id/edit", to: "announcement#edit", via: :get, as: :announcement_edit + match "/admin/announcements/:id", to: "announcement#update", via: :patch, as: :announcement_update + match "/admin/announcements/:id", to: "announcement#destroy", via: :delete, as: :announcement_destroy + end puts 'processing time of routes.rb: ' + "#{(Time.now - start).round(3).to_s.ljust(5, '0')}s".light_green end From e731d76d52f4a404b1c274fff49854bf59e8161c Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 21:54:40 +0100 Subject: [PATCH 09/15] Update admin/announcements routes to use has_role? --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index b63596a9..a79b0092 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -128,7 +128,7 @@ Rails.application.routes.draw do match '/:username/questions(/p/:page)', to: 'user#questions', via: 'get', as: :show_user_questions, defaults: {page: 1} constraints ->(req) { req.env['warden'].authenticate?(scope: :user) && - (req.env['warden'].user.admin?) } do + (req.env['warden'].user.has_role?(:administrator)) } do match "/admin/announcements", to: "announcement#index", via: :get, as: :announcement_index match "/admin/announcements", to: "announcement#create", via: :post, as: :announcement_create match "/admin/announcements/new", to: "announcement#new", via: :get, as: :announcement_new From 80c6a4272a33c29b71d28024b22efb5962aeb284 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 21:58:08 +0100 Subject: [PATCH 10/15] Fix indentation in new.html.haml --- app/views/announcement/new.html.haml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/announcement/new.html.haml b/app/views/announcement/new.html.haml index 57ed3eaf..25942f28 100644 --- a/app/views/announcement/new.html.haml +++ b/app/views/announcement/new.html.haml @@ -2,15 +2,15 @@ .container.j2-page = bootstrap_form_for(@announcement, url: {action: "create"}) do |f| - if @announcement.errors.any? - .row - .col-md-12 - .alert.alert-danger - %strong - = pluralize(@announcement.errors.count, "error") - prohibited this announcement from being saved: - %ul - - @announcement.errors.full_messages.each do |err| - %li= err + .row + .col-md-12 + .alert.alert-danger + %strong + = pluralize(@announcement.errors.count, "error") + prohibited this announcement from being saved: + %ul + - @announcement.errors.full_messages.each do |err| + %li= err .row .col-md-12 = f.text_area :content, label: "Content" From 4889071f95dad21d71569fd6eb07bd0cf434acd6 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 22:27:50 +0100 Subject: [PATCH 11/15] Add JS for dismissing announcements --- app/assets/javascripts/announcement.coffee | 3 --- app/assets/javascripts/application.js.erb.coffee | 10 ++++++++++ app/assets/stylesheets/announcement.scss | 3 --- app/views/layouts/_profile.html.haml | 4 ++++ app/views/shared/_announcements.haml | 4 +++- 5 files changed, 17 insertions(+), 7 deletions(-) delete mode 100644 app/assets/javascripts/announcement.coffee delete mode 100644 app/assets/stylesheets/announcement.scss diff --git a/app/assets/javascripts/announcement.coffee b/app/assets/javascripts/announcement.coffee deleted file mode 100644 index 24f83d18..00000000 --- a/app/assets/javascripts/announcement.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/application.js.erb.coffee b/app/assets/javascripts/application.js.erb.coffee index b135cf66..73e9ef73 100644 --- a/app/assets/javascripts/application.js.erb.coffee +++ b/app/assets/javascripts/application.js.erb.coffee @@ -74,6 +74,16 @@ _ready = -> lineColor: bodyColor density: 23000 + $(".alert-announcement").each -> + aId = $(this)[0].dataset.announcementId + unless (window.localStorage.getItem("announcement#{aId}")) + $(this).toggleClass("hidden") + + $(document).on "click", ".alert-announcement button.close", (evt) -> + announcement = event.target.closest(".alert-announcement") + aId = announcement.dataset.announcementId + window.localStorage.setItem("announcement#{aId}", true) + $('.arctic_scroll').arctic_scroll speed: 500 diff --git a/app/assets/stylesheets/announcement.scss b/app/assets/stylesheets/announcement.scss deleted file mode 100644 index e922d541..00000000 --- a/app/assets/stylesheets/announcement.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the announcement controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/views/layouts/_profile.html.haml b/app/views/layouts/_profile.html.haml index d01c7293..519195db 100644 --- a/app/views/layouts/_profile.html.haml +++ b/app/views/layouts/_profile.html.haml @@ -28,6 +28,10 @@ %a{href: pghero_path} %i.fa.fa-fw.fa-database Database Monitor + %li + %a{href: announcement_index_path} + %i.fa.fa-fw.fa-info + Announcements %li.divider - if current_user.mod? %li diff --git a/app/views/shared/_announcements.haml b/app/views/shared/_announcements.haml index 6885694d..99fa74d6 100644 --- a/app/views/shared/_announcements.haml +++ b/app/views/shared/_announcements.haml @@ -1,6 +1,8 @@ .container.announcements - @active_announcements.each do |announcement| - .alert.alert-announcement + .alert.alert-announcement.alert-info.alert-dismissable.hidden{ data: { 'announcement-id': announcement.id } } + %button.close{ type: "button", "data-dismiss" => "alert" } + %span{ "aria-hidden" => "true" } × %p= announcement.content - if announcement.link_present? %a.alert-link{ href: announcement.link_href }= announcement.link_text From 864d5844dc189ae5b103cf4cc3d3b4da7cbaf09b Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 22:38:01 +0100 Subject: [PATCH 12/15] Add Announcement tests --- Gemfile | 1 + Gemfile.lock | 2 ++ spec/models/announcement_spec.rb | 50 +++++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index e20ff191..43a669b7 100644 --- a/Gemfile +++ b/Gemfile @@ -104,4 +104,5 @@ group :development, :test do gem 'letter_opener' # Use this just in local test environments gem 'brakeman' gem 'guard-brakeman' + gem 'timecop' end diff --git a/Gemfile.lock b/Gemfile.lock index c70c9ee6..ee793309 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -456,6 +456,7 @@ GEM thor (1.0.1) thread_safe (0.3.6) tilt (2.0.10) + timecop (0.9.1) tiny-color-rails (0.0.2) railties (>= 3.0) turbolinks (2.5.4) @@ -566,6 +567,7 @@ DEPENDENCIES simplecov-rcov spring (~> 2.0) sweetalert-rails + timecop tiny-color-rails tumblr_client! turbolinks (~> 2.5.3) diff --git a/spec/models/announcement_spec.rb b/spec/models/announcement_spec.rb index 0bfc218b..35a76d78 100644 --- a/spec/models/announcement_spec.rb +++ b/spec/models/announcement_spec.rb @@ -1,5 +1,47 @@ -require 'rails_helper' +# frozen_string_literal: true -RSpec.describe Announcement, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end +require "rails_helper" + +RSpec.describe(Announcement, type: :model) do + let!(:user) { FactoryBot.create :user } + let!(:me) do + Announcement.new( + content: "Raccoon", + starts_at: Time.current, + ends_at: Time.current + 1.day, + user: user + ) + end + + describe "#active?" do + it "returns true when the current time is between starts_at and ends_at" do + expect(me.active?).to be(true) + end + + it "returns false when the current time is before starts_at" do + Timecop.freeze(me.starts_at - 1.second) + expect(me.active?).to be(false) + Timecop.return + end + + it "returns false when the current time is after ends_at" do + Timecop.freeze(me.ends_at) + expect(me.active?).to be(false) + Timecop.return + end + end + + describe "#link_present?" do + it "returns true if a link is present" do + me.link_text = "Very good dogs" + me.link_href = "https://www.reddit.com/r/rarepuppers/" + expect(me.link_present?).to be(true) + end + + it "returns false if a link is not present" do + me.link_text = nil + me.link_href = nil + expect(me.link_present?).to be(false) + end + end +end \ No newline at end of file From c4164a8f343bef7c44ad2c45a0bb91e2c8ed0791 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 22:40:06 +0100 Subject: [PATCH 13/15] Add AnnouncementController tests --- Gemfile | 1 + Gemfile.lock | 5 + .../announcement_controller_spec.rb | 159 ++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 spec/controllers/announcement_controller_spec.rb diff --git a/Gemfile b/Gemfile index 43a669b7..f81e1de1 100644 --- a/Gemfile +++ b/Gemfile @@ -105,4 +105,5 @@ group :development, :test do gem 'brakeman' gem 'guard-brakeman' gem 'timecop' + gem 'rails-controller-testing' end diff --git a/Gemfile.lock b/Gemfile.lock index ee793309..fd7eed2a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -344,6 +344,10 @@ GEM rails-assets-growl (1.3.5) rails-assets-jquery rails-assets-jquery (2.2.4) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) @@ -551,6 +555,7 @@ DEPENDENCIES rails (~> 5.2) rails-assets-growl! rails-assets-jquery (~> 2.2.0)! + rails-controller-testing rails-i18n (~> 5.0) rails_admin rake diff --git a/spec/controllers/announcement_controller_spec.rb b/spec/controllers/announcement_controller_spec.rb new file mode 100644 index 00000000..51649e3c --- /dev/null +++ b/spec/controllers/announcement_controller_spec.rb @@ -0,0 +1,159 @@ +# frozen_string_literal: true + +require "rails_helper" + +describe AnnouncementController, type: :controller do + let(:user) { FactoryBot.create(:user) } + before(:each) { user.add_role :administrator } + + describe "#index" do + subject { get :index } + + context "user signed in" do + before(:each) { sign_in(user) } + + it "renders the index template" do + subject + expect(response).to render_template(:index) + end + + context "no announcements" do + it "@announcements is empty" do + subject + expect(assigns(:announcements)).to be_blank + end + end + + context "one announcement" do + let!(:announcement) { Announcement.create(content: "I am announcement", user: user, starts_at: Time.current, ends_at: Time.current + 2.days) } + + it "includes the announcement in the @announcements assign" do + subject + expect(assigns(:announcements)).to include(announcement) + end + end + end + end + + describe "#new" do + subject { get :new } + + context "user signed in" do + before(:each) { sign_in(user) } + + it "renders the new template" do + subject + expect(response).to render_template(:new) + end + end + end + + describe "#create" do + let :announcement_params do + { + announcement: { + content: "I like dogs!", + starts_at: Time.current, + ends_at: Time.current + 2.days + } + } + end + + subject { post :create, params: announcement_params } + + context "user signed in" do + before(:each) { sign_in(user) } + + it "creates an announcement" do + expect { subject }.to change { Announcement.count }.by(1) + end + + it "redirects to announcement#index" do + subject + expect(response).to redirect_to(:announcement_index) + end + end + end + + describe "#edit" do + let! :announcement do + Announcement.create(content: "Dogs are pretty cool, I guess", + starts_at: Time.current + 3.days, + ends_at: Time.current + 10.days, + user: user) + end + + subject { get :edit, params: { id: announcement.id } } + + context "user signed in" do + before(:each) { sign_in(user) } + + it "renders the edit template" do + subject + expect(response).to render_template(:edit) + end + end + end + + describe "#update" do + let :announcement_params do + { + content: "The trebuchet is the superior siege weapon" + } + end + + let! :announcement do + Announcement.create(content: "Dogs are pretty cool, I guess", + starts_at: Time.current + 3.days, + ends_at: Time.current + 10.days, + user: user) + end + + subject do + patch :update, params: { + id: announcement.id, + announcement: announcement_params + } + end + + context "user signed in" do + before(:each) { sign_in(user) } + + it "updates the announcement" do + subject + updated = Announcement.find announcement.id + expect(updated.content).to eq(announcement_params[:content]) + end + + it "redirects to announcement#index" do + subject + expect(response).to redirect_to(:announcement_index) + end + end + end + + describe "#destroy" do + let! :announcement do + Announcement.create(content: "Dogs are pretty cool, I guess", + starts_at: Time.current + 3.days, + ends_at: Time.current + 10.days, + user: user) + end + + subject { delete :destroy, params: { id: announcement.id } } + + context "user signed in" do + before(:each) { sign_in(user) } + + it "deletes the announcement" do + expect { subject }.to change { Announcement.count }.by(-1) + end + + it "redirects to announcement#index" do + subject + expect(response).to redirect_to(:announcement_index) + end + end + end +end + From 16ade832ca9a6e63bf026168d8995850925c7c74 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 22:58:47 +0100 Subject: [PATCH 14/15] Address @nilsding's review changes --- config/routes.rb | 17 +++++++---------- spec/helpers/announcement_helper_spec.rb | 15 --------------- 2 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 spec/helpers/announcement_helper_spec.rb diff --git a/config/routes.rb b/config/routes.rb index a79b0092..5d3e2464 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,6 +10,13 @@ Rails.application.routes.draw do mount Sidekiq::Web, at: "/sidekiq" mount PgHero::Engine, at: "/pghero", as: "pghero" + + match "/admin/announcements", to: "announcement#index", via: :get, as: :announcement_index + match "/admin/announcements", to: "announcement#create", via: :post, as: :announcement_create + match "/admin/announcements/new", to: "announcement#new", via: :get, as: :announcement_new + match "/admin/announcements/:id/edit", to: "announcement#edit", via: :get, as: :announcement_edit + match "/admin/announcements/:id", to: "announcement#update", via: :patch, as: :announcement_update + match "/admin/announcements/:id", to: "announcement#destroy", via: :delete, as: :announcement_destroy end # Moderation panel @@ -127,15 +134,5 @@ Rails.application.routes.draw do match '/:username/groups(/p/:page)', to: 'user#groups', via: 'get', as: :show_user_groups, defaults: {page: 1} match '/:username/questions(/p/:page)', to: 'user#questions', via: 'get', as: :show_user_questions, defaults: {page: 1} - constraints ->(req) { req.env['warden'].authenticate?(scope: :user) && - (req.env['warden'].user.has_role?(:administrator)) } do - match "/admin/announcements", to: "announcement#index", via: :get, as: :announcement_index - match "/admin/announcements", to: "announcement#create", via: :post, as: :announcement_create - match "/admin/announcements/new", to: "announcement#new", via: :get, as: :announcement_new - match "/admin/announcements/:id/edit", to: "announcement#edit", via: :get, as: :announcement_edit - match "/admin/announcements/:id", to: "announcement#update", via: :patch, as: :announcement_update - match "/admin/announcements/:id", to: "announcement#destroy", via: :delete, as: :announcement_destroy - end - puts 'processing time of routes.rb: ' + "#{(Time.now - start).round(3).to_s.ljust(5, '0')}s".light_green end diff --git a/spec/helpers/announcement_helper_spec.rb b/spec/helpers/announcement_helper_spec.rb deleted file mode 100644 index 04b6d9e2..00000000 --- a/spec/helpers/announcement_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'rails_helper' - -# Specs in this file have access to a helper object that includes -# the AnnouncementHelper. For example: -# -# describe AnnouncementHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# expect(helper.concat_strings("this","that")).to eq("this that") -# end -# end -# end -RSpec.describe AnnouncementHelper, type: :helper do - pending "add some examples to (or delete) #{__FILE__}" -end From 6e605758a6e447bfecd90988085edb5aa2b1ab72 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Sun, 19 Apr 2020 22:59:57 +0100 Subject: [PATCH 15/15] Minor cleanup in AnnouncementController --- spec/controllers/announcement_controller_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/controllers/announcement_controller_spec.rb b/spec/controllers/announcement_controller_spec.rb index 51649e3c..4af41374 100644 --- a/spec/controllers/announcement_controller_spec.rb +++ b/spec/controllers/announcement_controller_spec.rb @@ -3,8 +3,7 @@ require "rails_helper" describe AnnouncementController, type: :controller do - let(:user) { FactoryBot.create(:user) } - before(:each) { user.add_role :administrator } + let(:user) { FactoryBot.create(:user, roles: [:administrator]) } describe "#index" do subject { get :index }