Skip to content

Commit

Permalink
Allowing admins to create "app announcements" which are then shown to…
Browse files Browse the repository at this point in the history
… users until they are marked as viewed
  • Loading branch information
mkr committed Dec 22, 2023
1 parent 6e7d9fd commit a7e3415
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

//= require bootstrap/dist/js/bootstrap.bundle
//= require jquery
//= require rails-ujs

//= require vega
//= require vega-lite
Expand Down
54 changes: 54 additions & 0 deletions app/controllers/admin/app_announcements_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

module Admin
class AppAnnouncementsController < Admin::AdminController
def index
@app_announcements = AppAnnouncement.all
end

def show
@app_announcement = AppAnnouncement.find(params[:id])
end

def new
@app_announcement = AppAnnouncement.new
end

def edit
@app_announcement = AppAnnouncement.find(params[:id])
end

def create
@app_announcement = AppAnnouncement.new(app_announcement_params)
@app_announcement.author = current_user
@save_result = @app_announcement.save

if @save_result
redirect_to admin_app_announcements_path
else
render 'new'
end
end

def update
@app_announcement = AppAnnouncement.find(params[:id])
if @app_announcement.update(app_announcement_params)
redirect_to admin_app_announcements_path
else
render 'edit'
end
end

def destroy
@app_announcement = AppAnnouncement.find(params[:id])
@app_announcement.destroy
redirect_to admin_app_announcements_path
end

private

def app_announcement_params
params.require(:app_announcement).permit(:text, :author_id)
end
end
end
10 changes: 10 additions & 0 deletions app/controllers/app_announcements_viewed_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class AppAnnouncementsViewedController < ApplicationController
def create
@app_announcement = AppAnnouncement.find(params[:app_announcement_id])
@app_announcement_viewed = AppAnnouncementViewed.create(user: current_user, app_announcement: @app_announcement)

redirect_to root_path
end
end
28 changes: 28 additions & 0 deletions app/models/app_announcement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

# == Schema Information
#
# Table name: app_announcements
#
# id :bigint not null, primary key
# text :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# author_id :integer
#
class AppAnnouncement < ApplicationRecord
belongs_to :author, class_name: 'User'
has_many :app_announcement_viewed, dependent: :destroy
has_many :viewers, through: :app_announcement_viewed, source: :user

scope :latest_unseen_for_user, ->(user) {
join_condition = "
LEFT OUTER JOIN `app_announcement_vieweds`
ON `app_announcements`.`id` = `app_announcement_vieweds`.`app_announcement_id`
AND `app_announcement_vieweds`.`user_id` = ?
"
joins(sanitize_sql_array([ join_condition, user.id ]))
.where('`app_announcement_vieweds`.`user_id` IS NULL')
.order(created_at: :desc)
}
end
16 changes: 16 additions & 0 deletions app/models/app_announcement_viewed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

# == Schema Information
#
# Table name: app_announcement_vieweds
#
# id :bigint not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# app_announcement_id :integer
# user_id :integer
#
class AppAnnouncementViewed < ApplicationRecord
belongs_to :user
belongs_to :app_announcement
end
10 changes: 10 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ class User < ApplicationRecord
has_many :metadata,
dependent: :destroy

has_many :app_announcements, foreign_key: 'author_id', dependent: :destroy, inverse_of: :author
has_many :viewed_app_announcements, through: :app_announcements_viewed, source: :app_announcement

# Validations

# https://davidcel.is/posts/stop-validating-email-addresses-with-regex/
Expand Down Expand Up @@ -237,6 +240,13 @@ def pending_invite?
created_by_invite? && !invitation_accepted? && password.blank?
end

def unseen_app_notifications
AppAnnouncement
.left_outer_joins(:app_announcement_viewed)
.where('user_id != ? OR user_id IS NULL', id)
.order(:created_at)
end

private

def set_defaults
Expand Down
25 changes: 25 additions & 0 deletions app/views/admin/app_announcements/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Edit Quepid Announcement</h1>
</div>


<%= form_for [:admin, @app_announcement] do |form| %>

<div class="mb-3">
<%= form.label :text, class: 'form-label' %>
<%= form.text_field :text, required: true, class: 'form-control' %>
<div class="form-text">The announcement.</div>
</div>

<br>

<div class="actions">
<%= form.submit %>
</div>

<% end %>


<br>
<%= button_to 'Back to Quepid Announcements', admin_app_announcements_path, method: :get %>
<br>
37 changes: 37 additions & 0 deletions app/views/admin/app_announcements/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Quepid Announcements</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2">
<%= link_to 'New Quepid Announcement', new_admin_app_announcement_path, class: "btn btn-sm btn-outline-secondary" %>
</div>
</div>
</div>


<table class="table table-striped table-hover">

<thead>
<tr>
<th>Text</th>
<th>Author</th>
<th>Created</th>
<th>Views</th>
<th>Actions</th>
</tr>
</thead>

<tbody>
<% @app_announcements.each do |announcement| %>
<tr>
<td><%= announcement.text %></td>
<td><%= announcement.author.name %> </td>
<td><%= announcement.created_at.strftime("%B %d %Y, %l:%M%P") %> </td>
<td><%= announcement.app_announcement_viewed.size %> </td>
<td>
<%= link_to 'Edit', edit_admin_app_announcement_path(announcement) %>
<%= link_to 'Delete', admin_app_announcement_path(announcement), method: :delete, data: { confirm: 'Are you sure?' } %>
</td>
</tr>
<% end %>
</tbody>
</table>
25 changes: 25 additions & 0 deletions app/views/admin/app_announcements/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">New Quepid Announcement</h1>
</div>


<%= form_for [:admin, @app_announcement] do |form| %>

<div class="mb-3">
<%= form.label :text, class: 'form-label' %>
<%= form.text_field :text, required: true, class: 'form-control' %>
<div class="form-text">The announcement.</div>
</div>

<br>

<div class="actions">
<%= form.submit %>
</div>

<% end %>


<br>
<%= button_to 'Back to Quepid Announcements', admin_app_announcements_path, method: :get %>
<br>
23 changes: 23 additions & 0 deletions app/views/admin/app_announcements/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Quepid Announcements</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2">
<%= link_to 'New Quepid Announcement', new_admin_app_announcement_path, class: "btn btn-sm btn-outline-secondary" %>
</div>
</div>
</div>

<p>
Quepid announcements allow administrators to broadcast important information to all Quepid users.
</p>

<p>
<strong>Announcement:</strong>
<%= @app_announcement.text %>
</p>

<p>
<strong>Author:</strong>
<%= @app_announcement.author.name %>
</p>

19 changes: 19 additions & 0 deletions app/views/layouts/_header.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,25 @@
</div>
</nav>



<% if @current_user.present? %>
<% AppAnnouncement.latest_unseen_for_user(@current_user).each do |notification| %>
<div class="alert alert-info" role="alert" style="z-index: 100">
<%= notification.text.html_safe %>

<%= link_to app_announcement_app_announcements_viewed_index_path(notification), method: :post do %>
<i
class="bi bi-x-circle"
aria-hidden="true"
title="Mark as viewed"
></i>
<% end %>

</div>
<% end %>
<% end %>

<div id='flash'>
<%= flash_messages_bs5 -%>
</div>
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
resources :ratings, only: [ :index ]
end

resources :app_announcements, only: [] do
resources :app_announcements_viewed, only: [ :create ]
end

resources :books do
resources :judgements
resources :query_doc_pairs do
Expand Down Expand Up @@ -84,6 +88,7 @@
resource :pulse, only: [ :show ], module: :users
end
resources :communal_scorers
resources :app_announcements
end

# preview routes for mailers
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20231207104058_create_app_announcements.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateAppAnnouncements < ActiveRecord::Migration[7.0]
def change
create_table :app_announcements do |t|
t.string :text
t.integer :author_id

t.timestamps
end
end
end
10 changes: 10 additions & 0 deletions db/migrate/20231207110513_create_app_announcement_vieweds.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateAppAnnouncementVieweds < ActiveRecord::Migration[7.0]
def change
create_table :app_announcement_vieweds do |t|
t.integer :app_announcement_id
t.integer :user_id

t.timestamps
end
end
end
16 changes: 15 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a7e3415

Please sign in to comment.