ucb_site_announcements 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4333bc60de8c92e69d82330727edb8195c45a3016a53de499cf089ff8ed95fad
4
+ data.tar.gz: af80d23b82f4c658b765e32beb564117238345bd71c755b538ec8fd3a6fb3ace
5
+ SHA512:
6
+ metadata.gz: a6b028437b25fea81cf9d4e053097f31b282b44e8fa7caba535e3356e7aaf6076bdfc5bc3da78caf39bb407abd258763d4ad01f28732cfba79208c52924a1c07
7
+ data.tar.gz: 1fec7ee3d5c6e998df7d5ad824d3ebd688dbed2378bbb97d86692c8f0ace5cdb30be5cf9878c980d7835f8ba784fa191ea7b6d3e2bf77f4e09b4341462608885
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2023 Darin Wilson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Site Announcements Engine
2
+
3
+ The site_announcements engine provides administrator management and site display for timed announcements.
4
+
5
+ ## Prerequisites
6
+
7
+ * Ruby >= 3.0
8
+ * Rails >= 7.0
9
+
10
+ ## Installation
11
+
12
+ To add the engine to a Rails application:
13
+
14
+ 1. Add the gem to your Gemfile:
15
+
16
+ ```ruby
17
+ gem "site_announcements"
18
+ ```
19
+
20
+ 2. Run `bundle install`
21
+
22
+ 3. Mount the engine in `config/routes.rb`:
23
+
24
+ ```ruby
25
+ mount SiteAnnouncements::Engine => "/announcements" # set whatever URL you'd like to use here
26
+ ```
27
+
28
+ 4. Set up a configuration block in `config/initializers/site_announcements.rb` - `auth_callback` is required.
29
+
30
+ ```ruby
31
+ # config/initializers/site_announcements.rb
32
+ SiteAnnouncements.configure do |config|
33
+ config.auth_callback = ->(controller) {
34
+ # This will be called in the admin controller to determine if the current user can make changes
35
+ # to the announcements
36
+ #
37
+ # "controller" is the current controller instance so it will have access to anything defined in your
38
+ # ApplicationController
39
+ #
40
+ # Return true if the current user can view/edit announcements; false otherwise
41
+ #
42
+ # Example:
43
+ # controller.current_user.admin?
44
+ }
45
+ config.time_zone = "Pacific Time (US & Canada)"
46
+ end
47
+ ```
48
+
49
+ `time_zone` is optional, but will default to `Pacific Time (US & Canada)`
50
+
51
+ > [!CAUTION]
52
+ > If you don't provide a setting for `auth_callback` all users will be able to access the admin section for announcements, which is probably not what you want.
53
+
54
+ 5. Migrate the database:
55
+
56
+ ```
57
+ rake site_announcements:install:migrations
58
+ rake db:migrate
59
+ ```
60
+
61
+ ## Creating and Managing Announcements
62
+
63
+ Access the admin inteface at, e.g. `/announcements/admin` (assuming you set the mount point at `announcements` in step 3)
64
+
65
+ ## Displaying Announcements
66
+
67
+ To display active announcements in application views:
68
+
69
+ ```erb
70
+ <%= active_site_announcements %>
71
+ ```
72
+
73
+ This will render Bootstrap alert components for each active announcement.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/site_announcements .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,66 @@
1
+ module SiteAnnouncements
2
+ class AnnouncementsController < ::ApplicationController
3
+ around_action :set_time_zone
4
+ before_action :check_auth
5
+ before_action :set_announcement, only: [:show, :edit, :update, :destroy]
6
+
7
+ def index
8
+ @announcements = Announcement.all
9
+ end
10
+
11
+ def show
12
+ end
13
+
14
+ def new
15
+ @announcement = Announcement.new
16
+ end
17
+
18
+ def edit
19
+ end
20
+
21
+ def create
22
+ @announcement = Announcement.new(announcement_params)
23
+
24
+ if @announcement.save
25
+ redirect_to announcements_url, notice: "Announcement was successfully created."
26
+ else
27
+ render :new
28
+ end
29
+ end
30
+
31
+ def update
32
+ if @announcement.update(announcement_params)
33
+ redirect_to announcements_url, notice: "Announcement was successfully updated."
34
+ else
35
+ render :edit
36
+ end
37
+ end
38
+
39
+ def destroy
40
+ @announcement.destroy
41
+ redirect_to announcements_url, notice: "Announcement was successfully destroyed."
42
+ end
43
+
44
+ private
45
+
46
+ def set_time_zone(&block)
47
+ Time.use_zone(SiteAnnouncements.time_zone, &block)
48
+ end
49
+
50
+ def check_auth
51
+ callback = SiteAnnouncements.auth_callback
52
+ if callback.present? && !callback.call(self)
53
+ redirect_to "/", alert: "You are not authorized to access this page"
54
+ end
55
+ end
56
+
57
+ def set_announcement
58
+ @announcement = Announcement.find(params[:id])
59
+ end
60
+
61
+ def announcement_params
62
+ params.require(:announcement).permit(:message, :category, :start_time, :end_time, :enabled)
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ module SiteAnnouncements
2
+ module ApplicationHelper
3
+ def active_site_announcements
4
+ Announcement.active.map do |a|
5
+ content_tag(:div, a.message, class: "alert alert-#{a.category}")
6
+ end.join.html_safe
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module SiteAnnouncements
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module SiteAnnouncements
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,27 @@
1
+ module SiteAnnouncements
2
+ class Announcement < ApplicationRecord
3
+ validates_presence_of :message, :category
4
+
5
+ def self.active
6
+ now = Time.zone.now
7
+
8
+ self
9
+ .where(enabled: true)
10
+ .where("(start_time IS NULL OR start_time < :now) AND (end_time IS NULL OR end_time > :now)", now: now)
11
+ end
12
+
13
+ def formatted_start_time
14
+ format_datetime(start_time)
15
+ end
16
+
17
+ def formatted_end_time
18
+ format_datetime(end_time)
19
+ end
20
+
21
+ private
22
+
23
+ def format_datetime(datetime)
24
+ datetime&.strftime("%m/%d/%Y %I:%M %P")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ module SiteAnnouncements
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,49 @@
1
+ <div class="row">
2
+ <div class="col-md-8">
3
+ <%= form_with(model: @announcement) do |form| %>
4
+ <% if @announcement.errors.any? %>
5
+ <div class="alert alert-danger">
6
+ <ul>
7
+ <% @announcement.errors.full_messages.each do |msg| %>
8
+ <li><%= msg %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div class="mb-3 form-group">
15
+ <%= form.label :message %>
16
+ <%= form.text_field :message, class: "form-control" %>
17
+ </div>
18
+
19
+ <div class="mb-3 form-group">
20
+ <%= form.label :category %>
21
+ <%= form.select :category, [["Info", "info"], ["Warning", "warning"], ["Danger", "danger"]], { prompt: "Choose a category" }, { class: "form-control" } %>
22
+ </div>
23
+
24
+ <div class="row">
25
+ <div class="col-md-6 form-group">
26
+ <%= form.label :start_time %>
27
+ <%= form.datetime_field :start_time, class: "form-control" %>
28
+ </div>
29
+
30
+ <div class="col-md-6 form-group">
31
+ <%= form.label :end_time %>
32
+ <%= form.datetime_field :end_time, class: "form-control" %>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="form-check">
37
+ <%= form.check_box :enabled %>
38
+ <%= form.label :enabled %>
39
+ </div>
40
+
41
+ <div class="form-group">
42
+ <%= form.submit class: "btn btn-primary" %>
43
+ &nbsp;
44
+ <%= link_to "Cancel", :back %>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <h1>Editing Announcement</h1>
2
+
3
+ <%= render 'form', announcement: @announcement %>
@@ -0,0 +1,35 @@
1
+ <h1>Announcements</h1>
2
+
3
+ <div class="mb-3">
4
+ <%= link_to "New Announcement", new_announcement_path, class: "btn btn-primary" %>
5
+ </div>
6
+
7
+ <table class="table table-striped">
8
+ <thead>
9
+ <tr>
10
+ <th>Message</th>
11
+ <th>Category</th>
12
+ <th>Enabled</th>
13
+ <th>Start Time</th>
14
+ <th>End Time</th>
15
+ <th colspan="2"></th>
16
+ </tr>
17
+ </thead>
18
+
19
+ <tbody>
20
+ <% @announcements.each do |announcement| %>
21
+ <tr>
22
+ <td><%= announcement.message %></td>
23
+ <td><%= announcement.category %></td>
24
+ <td><%= announcement.enabled ? "Yes" : "No" %></td>
25
+ <td><%= announcement.formatted_start_time %></td>
26
+ <td><%= announcement.formatted_end_time %></td>
27
+ <td><%= link_to "Edit", edit_announcement_path(announcement) %></td>
28
+ <td><%= button_to "Delete", announcement_url(announcement), method: :delete, class: "btn btn-danger",
29
+ onclick: "return confirm('Are you sure?')" %></td>
30
+ </tr>
31
+ <% end %>
32
+ </tbody>
33
+ </table>
34
+
35
+ <br>
@@ -0,0 +1,3 @@
1
+ <h1>New Announcement</h1>
2
+
3
+ <%= render 'form', announcement: @announcement %>
@@ -0,0 +1,27 @@
1
+ <p>
2
+ <strong>Message:</strong>
3
+ <%= @announcement.message %>
4
+ </p>
5
+
6
+ <p>
7
+ <strong>Category:</strong>
8
+ <%= @announcement.category %>
9
+ </p>
10
+
11
+ <p>
12
+ <strong>Start Time:</strong>
13
+ <%= @announcement.formatted_start_time %>
14
+ </p>
15
+
16
+ <p>
17
+ <strong>End Time:</strong>
18
+ <%= @announcement.formatted_end_time %>
19
+ </p>
20
+
21
+ <p>
22
+ <strong>Enabled:</strong>
23
+ <%= @announcement.enabled ? "Yes" : "No" %>
24
+ </p>
25
+
26
+ <%= link_to 'Edit', edit_announcement_path(@announcement) %> |
27
+ <%= link_to 'Back', announcements_path %>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ SiteAnnouncements::Engine.routes.draw do
2
+ resources :announcements
3
+ root to: "announcements#index"
4
+ end
@@ -0,0 +1,15 @@
1
+ class CreateSiteAnnouncementsAnnouncements < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :site_announcements_announcements do |t|
4
+ t.string :message, null: false
5
+ t.string :category, null: false
6
+ t.datetime :start_time
7
+ t.datetime :end_time
8
+ t.boolean :enabled, null: false, default: true
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :site_announcements_announcements, :start_time
13
+ add_index :site_announcements_announcements, :end_time
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module SiteAnnouncements
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace SiteAnnouncements
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec
7
+ end
8
+
9
+ initializer 'local_helper.action_controller' do
10
+ ActiveSupport.on_load :action_controller do
11
+ helper SiteAnnouncements::ApplicationHelper
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module SiteAnnouncements
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,14 @@
1
+ require "site_announcements/version"
2
+ require "site_announcements/engine"
3
+
4
+ module SiteAnnouncements
5
+ mattr_accessor :time_zone
6
+ mattr_accessor :auth_callback
7
+
8
+ def self.configure(&block)
9
+ configuration = OpenStruct.new(time_zone: Time.zone, auth_callback: nil)
10
+ yield configuration if block
11
+ self.time_zone = configuration.time_zone || "Pacific Time (US & Canada)"
12
+ self.auth_callback = configuration.auth_callback
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :site_announcements do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ucb_site_announcements
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Darin Wilson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: standard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 6.1.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 6.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: capybara
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: capybara-screenshot
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: selenium-webdriver
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: A Rails engine for site-wide announcement banners
98
+ email:
99
+ - darinwilson@berkeley.edu
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - MIT-LICENSE
105
+ - README.md
106
+ - Rakefile
107
+ - app/assets/config/site_announcements_manifest.js
108
+ - app/assets/stylesheets/site_announcements/application.css
109
+ - app/controllers/site_announcements/announcements_controller.rb
110
+ - app/helpers/site_announcements/application_helper.rb
111
+ - app/jobs/site_announcements/application_job.rb
112
+ - app/mailers/site_announcements/application_mailer.rb
113
+ - app/models/site_announcements/announcement.rb
114
+ - app/models/site_announcements/application_record.rb
115
+ - app/views/site_announcements/announcements/_form.html.erb
116
+ - app/views/site_announcements/announcements/edit.html.erb
117
+ - app/views/site_announcements/announcements/index.html.erb
118
+ - app/views/site_announcements/announcements/new.html.erb
119
+ - app/views/site_announcements/announcements/show.html.erb
120
+ - config/routes.rb
121
+ - db/migrate/20231206192929_create_site_announcements_announcements.rb
122
+ - lib/site_announcements.rb
123
+ - lib/site_announcements/engine.rb
124
+ - lib/site_announcements/version.rb
125
+ - lib/tasks/site_announcements_tasks.rake
126
+ homepage: https://github.com/ucb-ist-eas/site_announcements
127
+ licenses:
128
+ - MIT
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubygems_version: 3.2.33
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: A Rails engine for site-wide announcement banners
149
+ test_files: []