Merge pull request #9638 from colinux/poc-release-notes
ETQ super-admin je peux informer les administrateurs, instructeurs et experts des évolutions du site
This commit is contained in:
commit
7a4456efeb
33 changed files with 598 additions and 6 deletions
|
@ -2,6 +2,8 @@ class ApplicationComponent < ViewComponent::Base
|
|||
include ViewComponent::Translatable
|
||||
include FlipperHelper
|
||||
|
||||
delegate :rich_text_area_tag, to: :helpers
|
||||
|
||||
def current_user
|
||||
controller.current_user
|
||||
end
|
||||
|
|
31
app/components/release_note/form_component.rb
Normal file
31
app/components/release_note/form_component.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ReleaseNote::FormComponent < ApplicationComponent
|
||||
attr_reader :release_note
|
||||
|
||||
def initialize(release_note:)
|
||||
@release_note = release_note
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def categories_fieldset_class
|
||||
class_names(
|
||||
"fr-fieldset--error": categories_error?
|
||||
)
|
||||
end
|
||||
|
||||
def categories_error?
|
||||
release_note.errors.key?(:categories)
|
||||
end
|
||||
|
||||
def categories_errors_describedby_id
|
||||
return nil if !categories_error?
|
||||
|
||||
dom_id(release_note, "categories_errors")
|
||||
end
|
||||
|
||||
def categories_full_messages_errors
|
||||
release_note.errors.full_messages_for(:categories)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
en:
|
||||
delete: Delete this note
|
||||
new: New note
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fr:
|
||||
delete: Supprimer cette note
|
||||
new: Ajouter une note
|
|
@ -0,0 +1,53 @@
|
|||
= form_for [:super_admins, release_note] do |f|
|
||||
%fieldset#release_notes_fieldset.fr-fieldset{ 'data-controller': 'trix' }
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :released_on, input_type: :date_field) do |c|
|
||||
- c.with_label { ReleaseNote.human_attribute_name(:released_on) }
|
||||
|
||||
.fr-fieldset__element
|
||||
.fr-toggle
|
||||
= f.check_box :published, class: "fr-toggle-input", id: dom_id(release_note, :published)
|
||||
%label.fr-toggle__label{ for: dom_id(release_note, :published), data: { fr_checked_label: "Publié", fr_unchecked_label: "Brouillon" } }
|
||||
Publier
|
||||
|
||||
.fr-fieldset__element
|
||||
%fieldset.fr-fieldset{ "aria-labelledby": token_list(dom_id(release_note, "category_legend"), categories_errors_describedby_id), class: categories_fieldset_class, role: categories_error? ? "group" : nil }
|
||||
%legend.fr-fieldset__legend.fr-fieldset__legend--regular{ id: dom_id(release_note, :category_legend) }
|
||||
= ReleaseNote.human_attribute_name(:categories)
|
||||
= render EditableChamp::AsteriskMandatoryComponent.new
|
||||
|
||||
- ReleaseNote::CATEGORIES.each do |category|
|
||||
.fr-fieldset__element.fr-fieldset__element--inline
|
||||
.fr-checkbox-group
|
||||
= f.check_box :categories, { multiple: true, include_hidden: false, id: dom_id(release_note, "category_#{category}"), "aria-describedby" => "#{dom_id(release_note, "category_#{category}_messages")}" }, category, nil
|
||||
%label.fr-label{ for: dom_id(release_note, "category_#{category}") }
|
||||
= category.humanize
|
||||
|
||||
- if categories_error?
|
||||
.fr-messages-group{ id: "checkboxes-error-messages", aria_live: "assertive" }
|
||||
- if categories_full_messages_errors.one?
|
||||
%p.fr-message.fr-message--error{ id: categories_errors_describedby_id }= categories_full_messages_errors.first
|
||||
- else
|
||||
.fr-error-text{ id: categories_errors_describedby_id }
|
||||
%ul.list-style-type-none.fr-pl-0
|
||||
- categories_full_messages_errors.map do |error_message|
|
||||
%li= error_message
|
||||
|
||||
|
||||
.fr-fieldset__element
|
||||
.fr-input-group
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :body, input_type: :rich_text_area)
|
||||
|
||||
|
||||
.fr-fieldset__element
|
||||
%ul.fr-btns-group.fr-btns-group--inline.fr-btns-group--icon-left
|
||||
%li= f.button "Valider", class: "fr-btn fr-icon-check-line"
|
||||
|
||||
- if release_note.persisted?
|
||||
%li= link_to t(".new"), new_super_admins_release_note_path(date: release_note.released_on), class: "fr-btn fr-btn--secondary fr-icon-add-line"
|
||||
|
||||
- if release_note.persisted?
|
||||
%li
|
||||
= link_to t('.delete'), super_admins_release_note_path(release_note),
|
||||
class: "fr-btn fr-btn--secondary fr-icon-delete-line",
|
||||
data: { method: :delete, confirm: "Supprimer cette note ?" }
|
45
app/controllers/release_notes_controller.rb
Normal file
45
app/controllers/release_notes_controller.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
class ReleaseNotesController < ApplicationController
|
||||
before_action :ensure_access_allowed!
|
||||
|
||||
def index
|
||||
@categories = params[:categories].presence || infer_default_categories
|
||||
|
||||
# Paginate per group of dates, then show all announces for theses dates
|
||||
@paginated_groups = ReleaseNote.published
|
||||
.for_categories(@categories)
|
||||
.select(:released_on)
|
||||
.group(:released_on)
|
||||
.order(released_on: :desc)
|
||||
.page(params[:page]).per(5)
|
||||
|
||||
@announces = ReleaseNote.where(released_on: @paginated_groups.map(&:released_on))
|
||||
.with_rich_text_body
|
||||
.for_categories(@categories)
|
||||
.order(released_on: :desc, id: :asc)
|
||||
|
||||
render "scrollable_list" if params[:page].present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def infer_default_categories
|
||||
if administrateur_signed_in?
|
||||
['administrateur', 'usager', current_administrateur.api_tokens.exists? ? 'api' : nil]
|
||||
elsif instructeur_signed_in?
|
||||
['instructeur', 'expert']
|
||||
elsif expert_signed_in?
|
||||
['expert']
|
||||
else
|
||||
['usager']
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_access_allowed!
|
||||
return if administrateur_signed_in?
|
||||
return if instructeur_signed_in?
|
||||
return if expert_signed_in?
|
||||
|
||||
flash[:alert] = t('release_notes.index.forbidden')
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
62
app/controllers/super_admins/release_notes_controller.rb
Normal file
62
app/controllers/super_admins/release_notes_controller.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
class SuperAdmins::ReleaseNotesController < ApplicationController
|
||||
before_action :authenticate_super_admin!
|
||||
before_action :set_note, only: [:edit, :update, :destroy]
|
||||
|
||||
def nav_bar_profile
|
||||
:superadmin
|
||||
end
|
||||
|
||||
def index
|
||||
@release_notes = ReleaseNote
|
||||
.order(released_on: :desc, id: :asc)
|
||||
.with_rich_text_body
|
||||
end
|
||||
|
||||
def show
|
||||
# allows refreshing a submitted page in error
|
||||
redirect_to edit_super_admins_release_note_path(params[:id])
|
||||
end
|
||||
|
||||
def new
|
||||
@release_note = ReleaseNote.new(released_on: params[:date].presence || Date.current, published: true)
|
||||
end
|
||||
|
||||
def create
|
||||
@release_note = ReleaseNote.new(release_note_params)
|
||||
if @release_note.save
|
||||
redirect_to edit_super_admins_release_note_path(@release_note), notice: t('.success')
|
||||
else
|
||||
flash.now[:alert] = [t('.error'), @release_note.errors.full_messages].flatten
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@release_note = ReleaseNote.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
if @release_note.update(release_note_params)
|
||||
redirect_to edit_super_admins_release_note_path(@release_note), notice: t('.success')
|
||||
else
|
||||
flash.now[:alert] = [t('.error'), @release_note.errors.full_messages].flatten
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@release_note.destroy!
|
||||
|
||||
redirect_to super_admins_release_notes_path, notice: t('.success')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def release_note_params
|
||||
params.require(:release_note).permit(:released_on, :published, :body, categories: [])
|
||||
end
|
||||
|
||||
def set_note
|
||||
@release_note = ReleaseNote.find(params[:id])
|
||||
end
|
||||
end
|
18
app/helpers/release_notes_helper.rb
Normal file
18
app/helpers/release_notes_helper.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
module ReleaseNotesHelper
|
||||
def announce_category_badge(category)
|
||||
color_class = case category.to_sym
|
||||
when :administrateur
|
||||
'fr-background-flat--blue-france fr-text-inverted--blue-france'
|
||||
when :instructeur
|
||||
'fr-background-contrast--yellow-tournesol'
|
||||
when :expert
|
||||
'fr-background-contrast--purple-glycine'
|
||||
when :usager
|
||||
'fr-background-contrast--green-emeraude'
|
||||
when :api
|
||||
'fr-background-contrast--blue-ecume'
|
||||
end
|
||||
|
||||
content_tag(:span, ReleaseNote.human_attribute_name("categories.#{category}"), class: "fr-badge #{color_class}")
|
||||
end
|
||||
end
|
17
app/models/release_note.rb
Normal file
17
app/models/release_note.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class ReleaseNote < ApplicationRecord
|
||||
has_rich_text :body
|
||||
|
||||
CATEGORIES = [
|
||||
'administrateur',
|
||||
'instructeur',
|
||||
'expert',
|
||||
'usager',
|
||||
'api'
|
||||
]
|
||||
|
||||
validates :categories, presence: true, inclusion: { in: CATEGORIES }
|
||||
validates :body, presence: true
|
||||
|
||||
scope :published, -> { where(published: true, released_on: ..Date.current) }
|
||||
scope :for_categories, -> (categories) { where("categories && ARRAY[?]::varchar[]", categories) }
|
||||
end
|
|
@ -36,7 +36,7 @@
|
|||
%span.fr-icon-refresh-line.fr-icon--sm
|
||||
= t('go_gestionnaire', scope: [:layouts])
|
||||
|
||||
- if super_admin_signed_in?
|
||||
- if super_admin_signed_in? && nav_bar_profile != :superadmin
|
||||
%li
|
||||
= link_to manager_root_path, class: "fr-nav__link" do
|
||||
%span.fr-icon-shield-line.fr-icon--sm
|
||||
|
|
|
@ -99,4 +99,8 @@
|
|||
- if current_user.expert && current_expert.avis_summary[:total] > 0
|
||||
= render partial: 'layouts/header/avis_tab', locals: { current_expert: current_expert }
|
||||
|
||||
- if content_for?(:navigation_principale)
|
||||
.fr-container
|
||||
= yield(:navigation_principale)
|
||||
|
||||
= yield(:notice_info)
|
||||
|
|
|
@ -24,8 +24,9 @@ as defined by the routes in the `admin/` namespace
|
|||
<hr />
|
||||
|
||||
<%= link_to "Delayed Jobs", manager_delayed_job_path, class: "navigation__link" %>
|
||||
<%= link_to "Features", manager_flipper_path, class: "navigation__link" %>
|
||||
<%= link_to "Maintenance Tasks", manager_maintenance_tasks_path, class: "navigation__link" %>
|
||||
<%= link_to "Features", manager_flipper_path, class: "navigation__link" %>
|
||||
<%= link_to "Annonces", super_admins_release_notes_path, class: "navigation__link" %>
|
||||
<%= link_to "Import data via CSV", manager_import_procedure_tags_path, class: "navigation__link" %>
|
||||
<% if Rails.application.secrets.sendinblue[:enabled] && ENV["SAML_IDP_ENABLED"] == "enabled" %>
|
||||
<%= link_to "Sendinblue", ENV.fetch("SENDINBLUE_LOGIN_URL"), class: "navigation__link", target: '_blank' %>
|
||||
|
|
10
app/views/release_notes/_announce.html.haml
Normal file
10
app/views/release_notes/_announce.html.haml
Normal file
|
@ -0,0 +1,10 @@
|
|||
.fr-mb-4w
|
||||
%h3= l(notes[0].released_on, format: :long)
|
||||
|
||||
- notes.each do |note|
|
||||
.fr-mb-4w.fr-px-2w.fr-py-2w.fr-background-alt--grey
|
||||
%p
|
||||
- note.categories.each do |category|
|
||||
= announce_category_badge(category)
|
||||
|
||||
= note.body
|
5
app/views/release_notes/_page.html.haml
Normal file
5
app/views/release_notes/_page.html.haml
Normal file
|
@ -0,0 +1,5 @@
|
|||
= render partial: 'announce', collection: announces.group_by(&:released_on).values, as: :notes
|
||||
|
||||
- if !paginated_groups.last_page?
|
||||
= turbo_frame_tag "announces-page-#{paginated_groups.next_page}", loading: :lazy, src: next_page_path(paginated_groups) do
|
||||
= link_to t('.previous_page'), next_page_path(paginated_groups), class: "fr-btn fr-btn--secondary"
|
27
app/views/release_notes/index.html.haml
Normal file
27
app/views/release_notes/index.html.haml
Normal file
|
@ -0,0 +1,27 @@
|
|||
.fr-container.fr-my-5w
|
||||
%h2.fr-mb-5w= t('.title', app_name: APPLICATION_NAME)
|
||||
|
||||
.fr-grid-row.fr-grid-row--gutters{ data: { turbo: 'true' } }
|
||||
.fr-col-md-3
|
||||
= form_with(url: release_notes_path, method: :get, data: { turbo_frame: 'announces', controller: 'autosubmit' }, html: { role: 'search' }) do |f|
|
||||
%fieldset.sidebar-filter
|
||||
%legend
|
||||
%ul
|
||||
%li.fr-py-2w.fr-pl-2w
|
||||
%fieldset.fr-fieldset{ "aria-labelledby": "sidebar_category_legend" }
|
||||
%legend.fr-fieldset__legend{ id: "sidebar_category_legend" }
|
||||
= ReleaseNote.human_attribute_name(:categories)
|
||||
|
||||
- ReleaseNote::CATEGORIES.each do |category|
|
||||
.fr-fieldset__element
|
||||
.fr-checkbox-group
|
||||
= f.check_box :categories, { multiple: true, include_hidden: false, id: "filter_category_#{category}", checked: @categories.include?(category) }, category, nil
|
||||
%label.fr-label{ for: "filter_category_#{category}" }
|
||||
= ReleaseNote.human_attribute_name("categories.#{category}")
|
||||
|
||||
.fr-col-md-9
|
||||
= turbo_frame_tag "announces", data: { turbo_action: :advance } do
|
||||
- if @announces.any?
|
||||
= render "page", announces: @announces, paginated_groups: @paginated_groups
|
||||
- else
|
||||
%p.fr-my-4w.text-center= t('.no_content')
|
2
app/views/release_notes/scrollable_list.html.haml
Normal file
2
app/views/release_notes/scrollable_list.html.haml
Normal file
|
@ -0,0 +1,2 @@
|
|||
= turbo_frame_tag "announces-page-#{@paginated_groups.current_page}" do
|
||||
= render 'page', announces: @announces, paginated_groups: @paginated_groups
|
|
@ -0,0 +1,17 @@
|
|||
- content_for(:navigation_principale) do
|
||||
.fr-container
|
||||
%nav.fr-nav#header-navigation{ role: "navigation", aria: { label: 'Menu principal annonces' } }
|
||||
%ul.fr-nav__list
|
||||
%li.fr-nav__item
|
||||
= link_to "Toutes les annonces", super_admins_release_notes_path, class: "fr-nav__link", target: "_self", aria: { current: action == :index ? "page" : nil }
|
||||
|
||||
%li.fr-nav__item
|
||||
= link_to("Nouvelle annonce", new_super_admins_release_note_path(date: @release_note&.released_on), class: "fr-nav__link", target: "_self", aria: { current: action == :new ? "page" : nil })
|
||||
|
||||
- if action == :edit
|
||||
%li.fr-nav__item
|
||||
= link_to "Annonce", '', class: "fr-nav__link", target: "_self", aria: { current: "page" }
|
||||
|
||||
%li.fr-nav__item
|
||||
= link_to "Annonces publiées", release_notes_path, class: "fr-nav__link", target: "_self"
|
||||
|
|
@ -0,0 +1 @@
|
|||
= turbo_stream.append 'release_notes_fieldset', render(ReleaseNote::NoteFormComponent.new(note: @release_note))
|
8
app/views/super_admins/release_notes/edit.html.haml
Normal file
8
app/views/super_admins/release_notes/edit.html.haml
Normal file
|
@ -0,0 +1,8 @@
|
|||
= render "main_navigation", action: :edit
|
||||
|
||||
.fr-container.fr-my-5w
|
||||
.fr-grid-row.fr-grid-row--center
|
||||
.fr-col-lg-10
|
||||
%h1.fr-h2 Annonce
|
||||
= render ReleaseNote::FormComponent.new(release_note: @release_note)
|
||||
|
31
app/views/super_admins/release_notes/index.html.haml
Normal file
31
app/views/super_admins/release_notes/index.html.haml
Normal file
|
@ -0,0 +1,31 @@
|
|||
= render "main_navigation", action: :index
|
||||
|
||||
.fr-container.fr-my-5w
|
||||
.fr-grid-row.fr-grid-row--center
|
||||
.fr-col-lg-10
|
||||
|
||||
%h1.fr-h2 Liste des annonces
|
||||
|
||||
-# haml-lint:disable ApplicationNameLinter
|
||||
= link_to "Releases sur GitHub", "https://github.com/demarches-simplifiees/demarches-simplifiees.fr/releases", **external_link_attributes
|
||||
-# haml-lint:enable ApplicationNameLinter
|
||||
|
||||
.fr-table
|
||||
%table
|
||||
%thead
|
||||
%th Annoncé le
|
||||
%th Publié ?
|
||||
%th Notes
|
||||
%th Actions
|
||||
%tbody
|
||||
- @release_notes.each do |note|
|
||||
%tr
|
||||
%td= l(note.released_on) if note.released_on
|
||||
%td
|
||||
- if note.published?
|
||||
%span.fr-badge.fr-badge--success.fr-badge--no-icon Publié
|
||||
- else
|
||||
%span.fr-badge.fr-badge--warning.fr-badge--no-icon Brouillon
|
||||
%td= note.body.to_plain_text.truncate_words(12)
|
||||
%td
|
||||
= link_to 'Modifier', edit_super_admins_release_note_path(note), class: 'fr-btn fr-btn--secondary'
|
7
app/views/super_admins/release_notes/new.html.haml
Normal file
7
app/views/super_admins/release_notes/new.html.haml
Normal file
|
@ -0,0 +1,7 @@
|
|||
= render "main_navigation", action: :new
|
||||
|
||||
.fr-container.fr-my-5w
|
||||
.fr-grid-row.fr-grid-row--center
|
||||
.fr-col-lg-10
|
||||
%h1.fr-h2 Nouvelle Annonce
|
||||
= render ReleaseNote::FormComponent.new(release_note: @release_note)
|
|
@ -86,10 +86,10 @@ module TPS
|
|||
# @see https://guides.rubyonrails.org/configuring.html#custom-configuration
|
||||
config.x.clamav.enabled = ENV.fetch("CLAMAV_ENABLED", "enabled") == "enabled"
|
||||
|
||||
config.view_component.generate_sidecar = true
|
||||
config.view_component.generate_locale = true
|
||||
config.view_component.generate_distinct_locale_files = true
|
||||
config.view_component.generate_preview = true
|
||||
config.view_component.generate.sidecar = true
|
||||
config.view_component.generate.locale = true
|
||||
config.view_component.generate.distinct_locale_files = true
|
||||
config.view_component.generate.preview = true
|
||||
config.view_component.show_previews_source = true
|
||||
config.view_component.default_preview_layout = 'component_preview'
|
||||
config.view_component.preview_paths << "#{Rails.root}/spec/components/previews"
|
||||
|
|
31
config/locales/release_notes.en.yml
Normal file
31
config/locales/release_notes.en.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
en:
|
||||
release_notes:
|
||||
index:
|
||||
title: What’s new on %{app_name} ? 🚀
|
||||
forbidden: You are not authorized to view the News page.
|
||||
no_content: No announcement here.
|
||||
page:
|
||||
previous_page: Previous announcements
|
||||
super_admins:
|
||||
release_notes:
|
||||
create: &save
|
||||
success: Release note was successfully saved.
|
||||
error: Release note was not saved.
|
||||
update:
|
||||
<<: *save
|
||||
destroy:
|
||||
success: Release note was successfully deleted.
|
||||
activerecord:
|
||||
attributes:
|
||||
release_note:
|
||||
body: Announce
|
||||
categories: Categories
|
||||
released_on: Publication date
|
||||
release_note/categories:
|
||||
administrateur: Administrator
|
||||
instructeur: Instructor
|
||||
expert: Expert
|
||||
api: API
|
||||
usager: User
|
||||
|
31
config/locales/release_notes.fr.yml
Normal file
31
config/locales/release_notes.fr.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
fr:
|
||||
release_notes:
|
||||
index:
|
||||
title: Quoi de neuf sur %{app_name} ? 🚀
|
||||
forbidden: Vous n’êtes pas autorisé(e) à consulter la page des Nouveautés.
|
||||
no_content: Aucune nouveauté annoncée de ce côté là.
|
||||
page:
|
||||
previous_page: Annonces précédentes
|
||||
super_admins:
|
||||
release_notes:
|
||||
create: &save
|
||||
success: L’annonce a été sauvegardée.
|
||||
error: L’annonce n’a pas pu être sauvegardée.
|
||||
update:
|
||||
<<: *save
|
||||
destroy:
|
||||
success: La note a été supprimée.
|
||||
activerecord:
|
||||
attributes:
|
||||
release_note:
|
||||
body: Annonce
|
||||
categories: Catégories
|
||||
released_on: Date de publication
|
||||
release_note/categories:
|
||||
administrateur: Administrateur
|
||||
instructeur: Instructeur
|
||||
expert: Expert
|
||||
api: API
|
||||
usager: Usager
|
||||
|
|
@ -16,6 +16,7 @@ en:
|
|||
instructeur: instructor
|
||||
administrateur: admin
|
||||
gestionnaire: admins group manager
|
||||
superadmin: super-admin
|
||||
expert: expert
|
||||
user: user
|
||||
guest: guest
|
||||
|
|
|
@ -16,6 +16,7 @@ fr:
|
|||
instructeur: instructeur
|
||||
administrateur: administrateur
|
||||
gestionnaire: gestionnaire
|
||||
superadmin: super-admin
|
||||
expert: expert
|
||||
user: usager
|
||||
guest: invité
|
||||
|
|
|
@ -125,6 +125,10 @@ Rails.application.routes.draw do
|
|||
passwords: 'super_admins/passwords'
|
||||
}
|
||||
|
||||
namespace :super_admins do
|
||||
resources :release_notes
|
||||
end
|
||||
|
||||
get 'super_admins/edit_otp', to: 'super_admins#edit_otp', as: 'edit_super_admin_otp'
|
||||
put 'super_admins/enable_otp', to: 'super_admins#enable_otp', as: 'enable_super_admin_otp'
|
||||
|
||||
|
@ -630,6 +634,8 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :release_notes, only: [:index]
|
||||
|
||||
if Rails.env.test?
|
||||
scope 'test/api_geo' do
|
||||
get 'regions' => 'api_geo_test#regions'
|
||||
|
|
15
db/migrate/20230912155425_create_release_notes.rb
Normal file
15
db/migrate/20230912155425_create_release_notes.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class CreateReleaseNotes < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :release_notes do |t|
|
||||
t.date :released_on
|
||||
t.boolean :published, default: false, null: false
|
||||
t.string :categories, array: true, default: []
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :release_notes, :released_on
|
||||
add_index :release_notes, :published
|
||||
add_index :release_notes, :categories, using: :gin
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class AddAnnouncesSeenAtToUsers < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :users, :announces_seen_at, :datetime, null: true, default: nil, precision: 6
|
||||
end
|
||||
end
|
12
db/schema.rb
12
db/schema.rb
|
@ -896,6 +896,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_26_161609) do
|
|||
t.index ["procedure_id"], name: "index_refused_mails_on_procedure_id"
|
||||
end
|
||||
|
||||
create_table "release_notes", force: :cascade do |t|
|
||||
t.string "categories", default: [], array: true
|
||||
t.datetime "created_at", null: false
|
||||
t.boolean "published", default: false, null: false
|
||||
t.date "released_on"
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["categories"], name: "index_release_notes_on_categories", using: :gin
|
||||
t.index ["published"], name: "index_release_notes_on_published"
|
||||
t.index ["released_on"], name: "index_release_notes_on_released_on"
|
||||
end
|
||||
|
||||
create_table "safe_mailers", force: :cascade do |t|
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.string "forced_delivery_method"
|
||||
|
@ -1021,6 +1032,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_26_161609) do
|
|||
create_table "users", id: :serial, force: :cascade do |t|
|
||||
t.datetime "confirmation_sent_at", precision: 6
|
||||
t.datetime "blocked_at", precision: 6
|
||||
t.datetime "announces_seen_at", precision: 6
|
||||
t.text "blocked_reason"
|
||||
t.string "confirmation_token"
|
||||
t.datetime "confirmed_at", precision: 6
|
||||
|
|
51
spec/controllers/release_notes_controller_spec.rb
Normal file
51
spec/controllers/release_notes_controller_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ReleaseNotesController, type: :controller do
|
||||
let!(:note_admin) { create(:release_note, categories: ['administrateur'], body: "Pour l'admin", released_on: Date.new(2023, 10, 15)) }
|
||||
let!(:note_instructeur) { create(:release_note, categories: ['instructeur'], body: "Pour l'instructeur", released_on: Date.new(2023, 10, 13)) }
|
||||
|
||||
let(:user) { nil }
|
||||
let(:admin) { create(:user, administrateur: build(:administrateur)) }
|
||||
let(:instructeur) { create(:user, instructeur: build(:instructeur)) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:current_user).and_return(user)
|
||||
end
|
||||
|
||||
describe 'GET index' do
|
||||
subject { get :index }
|
||||
|
||||
describe 'filtering' do
|
||||
before { subject }
|
||||
context 'user is admininistrateur' do
|
||||
let(:user) { admin }
|
||||
it { is_expected.to have_http_status(:ok) }
|
||||
it { expect(assigns(:announces)).to eq([note_admin]) }
|
||||
end
|
||||
|
||||
context 'user is instructeur' do
|
||||
let(:user) { instructeur }
|
||||
it { is_expected.to have_http_status(:ok) }
|
||||
it { expect(assigns(:announces)).to eq([note_instructeur]) }
|
||||
end
|
||||
|
||||
context 'user is expert' do
|
||||
let(:user) { create(:user, expert: build(:expert)) }
|
||||
it { expect(assigns(:announces)).to eq([]) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'acl' do
|
||||
before { subject }
|
||||
context 'user is normal' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it { is_expected.to be_redirection }
|
||||
end
|
||||
|
||||
context 'no user' do
|
||||
it { is_expected.to be_redirection }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,82 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe SuperAdmins::ReleaseNotesController, type: :controller do
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
|
||||
before do
|
||||
sign_in super_admin if super_admin.present?
|
||||
end
|
||||
|
||||
describe "acl" do
|
||||
context 'when user is not signed as super admin' do
|
||||
let(:super_admin) { nil }
|
||||
let!(:release_note) { create(:release_note, published: false) }
|
||||
|
||||
it 'is not allowed to post' do
|
||||
expect { post :create, params: { release_note: { released_on: Date.current, published: "0", body: "bam" } } }.not_to change(ReleaseNote, :count)
|
||||
expect(response.status).to eq(302)
|
||||
expect(flash[:alert]).to be_present
|
||||
end
|
||||
|
||||
it 'is not allowed to put' do
|
||||
expect {
|
||||
put :update, params: {
|
||||
id: release_note.id,
|
||||
release_note: {
|
||||
released_on: Date.current,
|
||||
published: "1",
|
||||
categories: release_note.categories,
|
||||
body: "hacked body"
|
||||
}
|
||||
}
|
||||
}.not_to change { release_note.reload.body }
|
||||
expect(response.status).to eq(302)
|
||||
expect(flash[:alert]).to be_present
|
||||
end
|
||||
|
||||
it 'is not allowed to index' do
|
||||
get :index
|
||||
expect(response.status).to eq(302)
|
||||
expect(flash[:alert]).to be_present
|
||||
end
|
||||
|
||||
it 'is not allowed to destroy' do
|
||||
delete :destroy, params: { id: release_note.id }
|
||||
expect(response.status).to eq(302)
|
||||
expect(flash[:alert]).to be_present
|
||||
expect(release_note.reload).to be_persisted
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is signed as super admin' do
|
||||
let(:release_note) { create(:release_note, published: false) }
|
||||
|
||||
it 'is allowed to post' do
|
||||
expect { post :create, params: { release_note: { categories: ['api'], released_on: Date.current, published: "0", body: "bam" } } }.to change(ReleaseNote, :count).by(1)
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
|
||||
it 'is allowed to put' do
|
||||
put :update, params: {
|
||||
id: release_note.id,
|
||||
release_note: {
|
||||
released_on: Date.current,
|
||||
published: "1",
|
||||
categories: release_note.categories,
|
||||
body: "new body"
|
||||
}
|
||||
}
|
||||
|
||||
release_note.reload
|
||||
expect(release_note.body.to_plain_text).to eq("new body")
|
||||
expect(release_note.published).to be_truthy
|
||||
end
|
||||
|
||||
it 'is allowed to destroy' do
|
||||
delete :destroy, params: { id: release_note.id }
|
||||
expect(flash[:notice]).to be_present
|
||||
expect { release_note.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
8
spec/factories/release_notes.rb
Normal file
8
spec/factories/release_notes.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
FactoryBot.define do
|
||||
factory :release_note do
|
||||
body { "Sample release note body" }
|
||||
categories { ReleaseNote::CATEGORIES.sample(1) }
|
||||
published { true }
|
||||
released_on { 1.day.ago.to_date }
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue