Skip to content

Commit

Permalink
[feat] split audience from visibility
Browse files Browse the repository at this point in the history
Essentially we go back to the original
  • Loading branch information
multiscan committed Jan 17, 2025
1 parent aa1d2e9 commit f60bf54
Show file tree
Hide file tree
Showing 36 changed files with 253 additions and 141 deletions.
62 changes: 37 additions & 25 deletions app/assets/stylesheets/main_backoffice.scss
Original file line number Diff line number Diff line change
Expand Up @@ -178,37 +178,49 @@ span.visibility {
}

// ---------------------------------------------------------------- new visibility
.visibility-radios {
.visibility-container {
margin-left: 1em;
background-color: #fff;
padding: 4px 4px 0 4px;
border-radius: 5px;
box-sizing: border-box;
display: inline-block;

label {
padding: 0.05em 0.2em;
display: inline-block;
margin-right: 0;
cursor: pointer;
border-bottom: 2px solid #fff;
border-radius: 15%;
span {
transition: transform .2s ease-in-out;
display: inline-flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
span.text {
font-size: 60%;
// line-height: 60%;
// margin-top: -1ex;
position: relative;
}
.visibility-radios {
border-bottom: 1px solid #d9d9d9;
label {
padding: 0.05em 0.2em;
display: inline-block;
margin-right: 0;
cursor: pointer;
border-bottom: 2px solid #fff;
border-radius: 15%;
span {
transition: transform .2s ease-in-out;
}
span:hover {
top: -0.5ex;
transform: scale(1.25);
color: var(--red);
}
}
span:hover {
top: -0.5ex;
transform: scale(1.25);
color: var(--red);
input[type="radio"] {
display: none;
}
}
input[type="radio"] {
display: none;
}
input[type="radio"]:checked + label {
box-shadow: inset 0 0 2px #666;
border-bottom: 2px solid var(--red);
span {
color: var(--red-dark);
input[type="radio"]:checked + label {
box-shadow: inset 0 0 2px #666;
border-bottom: 2px solid var(--red);
span {
color: var(--red-dark);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/awards_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def set_award
def award_params
params.require(:award).permit(
:location, :title_fr, :title_en, :year, :issuer,
:audience, :visible, :position
:audience, :visibility, :position
)
end
end
2 changes: 1 addition & 1 deletion app/controllers/boxes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,6 @@ def set_box

# Only allow a list of trusted parameters through.
def box_params
params.require(:box).permit(:audience, :position)
params.require(:box).permit(:audience, :visibility, :position)
end
end
2 changes: 1 addition & 1 deletion app/controllers/educations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def set_education
def education_params
params.require(:education).permit(
:title_en, :title_fr, :field_en, :field_fr, :director, :school,
:year_begin, :year_end, :position, :audience, :visible, :description_fr, :description_en
:year_begin, :year_end, :position, :audience, :visibility, :description_fr, :description_en
)
end
end
2 changes: 1 addition & 1 deletion app/controllers/experiences_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def set_experience
def experience_params
params.require(:experience).permit(
:location, :title_fr, :title_en, :year_begin, :year_end,
:audience, :visible, :position, :description_fr, :description_en
:audience, :visibility, :position, :description_fr, :description_en
)
end
end
2 changes: 1 addition & 1 deletion app/controllers/index_boxes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ def set_box

# Only allow a list of trusted parameters through.
def box_params
params.require(:index_box).permit(:audience)
params.require(:index_box).permit(:audience, :visibility)
end
end
2 changes: 1 addition & 1 deletion app/controllers/publications_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,6 @@ def set_publication
end

def publication_params
params.require(:publication).permit(:title, :journal, :year, :authors, :url, :position, :audience, :visible)
params.require(:publication).permit(:title, :journal, :year, :authors, :url, :position, :audience, :visibility)
end
end
2 changes: 1 addition & 1 deletion app/controllers/rich_text_boxes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def set_box
# Only allow a list of trusted parameters through.
def box_params
params.require(:rich_text_box).permit(
:audience,
:audience, :visibility,
:title_fr, :title_en, :content_fr, :content_en
)
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/socials_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def toggle
private

def social_params
params.require(:social).permit(:tag, :value, :audience)
params.require(:social).permit(:tag, :value, :audience, :visibility)
end

def set_profile
Expand Down
38 changes: 24 additions & 14 deletions app/helpers/profiles_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,34 +80,44 @@ def audience_selector2(form)
safe_join(content)
end

AUDIENCE_OPTIONS = [
{ label: 'public', icon: 'globe' },
{ label: 'intranet', icon: 'home' },
# {label: 'authenticated', icon: 'key'},
# {label: 'owner', icon: 'user-check'},
{ label: 'authenticated', icon: 'user-check' },
{ label: 'owner', icon: 'edit-3' },
{ label: 'hidden', icon: 'eye-off' }
].freeze

def audience_selector(form, with_stimulus: false)
id0 = "#{form.object_name.underscore}_#{form.object.id}"
id0 = "#{form.object_name.underscore}_audience_#{form.object.id}"
stim_data = { action: "input->visibility#onChange", "visibility-target": "radio" }
content = []
AUDIENCE_OPTIONS.each_with_index do |o, i|
AudienceLimitable::AUDIENCE_OPTIONS.each_with_index do |o, i|
id = "#{id0}_#{i}"
label_data = { label: form.object.audience_label(i) }
title = t "visibility.labels.#{o[:label]}"
content << if with_stimulus
form.radio_button(:audience, i, id: id, data: stim_data)
form.radio_button(:audience, i, id: id, data: stim_data.merge(label_data))
else
form.radio_button(:audience, i, id: id)
form.radio_button(:audience, i, id: id, data: label_data)
end
content << form.label("audience_#{i}".to_sym, tag.span(icon(o[:icon])), for: id, title: title)
end
content = safe_join(content)
tag.div(content, class: "visibility-radios")
end

def visibility_selector(form, with_stimulus: false)
id0 = "#{form.object_name.underscore}_visibility_#{form.object.id}"
stim_data = { action: "input->visibility#onChange", "visibility-target": "radio" }
content = []
AudienceLimitable::VISIBILITY_OPTIONS.each_with_index do |o, i|
id = "#{id0}_#{i}"
label_data = { label: form.object.visibility_label(i) }
title = t "visibility.labels.#{o[:label]}"
content << if with_stimulus
form.radio_button(:visibility, i, id: id, data: stim_data.merge(label_data))
else
form.radio_button(:visibility, i, id: id, data: label_data)
end
content << form.label("visibility_#{i}".to_sym, tag.span(icon(o[:icon])), for: id, title: title)
end
content = safe_join(content)
tag.div(content, class: "visibility-radios")
end

def show_attribute_switch(form, attr)
id = "ck_#{form.object_name.gsub(/[^a-z0-9]+/, '_').gsub(/_$/, '')}_#{attr}"
tag.div(class: 'custom-control custom-checkbox') do
Expand Down
15 changes: 9 additions & 6 deletions app/javascript/controllers/visibility_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,33 @@ import { Controller } from "@hotwired/stimulus"
import { put } from "@rails/request.js";

export default class extends Controller {
static values = { model: String };
static targets = [ "radio" ];
static values = { model: String, field: String };
static targets = [ "form", "radio", "label"];

connect() {
this.oldRadio = this.radioTargets.find((x) => x.checked);
this.url = this.formTarget.action;
this.recovering = false;
}

onChange() {
if (this.recovering) {
console.log("Recovering");
this.recovering = false;
return;
}

const newRadio = this.radioTargets.find((x) => x.checked);

const value = newRadio.value;
const url = this.element.action;
const label = newRadio.getAttribute('data-label');
// JS shit!
const body = {};
body[this.modelValue] = {'audience': value};
put(url, {body: body}).then((response) => {
body[this.modelValue] = {};
body[this.modelValue][this.fieldValue] = value;
put(this.url, {body: body}).then((response) => {
if (response.ok) {
this.oldRadio = newRadio;
this.labelTarget.textContent=label;
} else {
// TODO: add flash message on error
// prevent onChange to fire again
Expand Down
51 changes: 38 additions & 13 deletions app/models/concerns/audience_limitable.rb
Original file line number Diff line number Diff line change
@@ -1,43 +1,68 @@
# frozen_string_literal: true

# This could be nicely implemented as enum but it is not yet implemented for mysql
# audience: 0=world, 1=intranet, 2=authenticated user
# visibility: 0=public, 1=draft, 2=hidden
# TODO: write unit tests
# TODO: when importing legacy data:
# - visible => audience=0
# - hidden => audience=4
# - visible => audience=0, visibility=0
# - hidden => audience=0, visibility=2

module AudienceLimitable
AUDIENCE_OPTIONS = [
{ label: 'public', icon: 'globe' },
{ label: 'intranet', icon: 'home' },
{ label: 'authenticated', icon: 'user-check' }
].freeze

VISIBILITY_OPTIONS = [
{ label: 'published', icon: 'eye' },
{ label: 'draft', icon: 'edit-3' },
{ label: 'hidden', icon: 'eye-off' }
].freeze

extend ActiveSupport::Concern

included do
scope :world_visible, -> { where(audience: 0) }
scope :intranet_visible, -> { where(audience: 0...2) }
scope :auth_visible, -> { where(audience: 0...3) }
scope :owner_visible, -> { where(audience: 0...4) }
scope :for_audience, ->(audience) { where(audience: 0...(audience + 1)) }
validates :audience, numericality: { in: 0...5 }
# Reminder: ranges do not include the upper limit
scope :world_visible, -> { where(audience: 0, visibility: 0) }
scope :intranet_visible, -> { where(audience: 0...2, visibility: 0) }
scope :auth_visible, -> { where(audience: 0...3, visibility: 0) }
scope :owner_visible, -> { where(visibility: 0...2) }
scope :for_audience, ->(audience) { where(audience: 0...(audience + 1), visibility: 0) }
validates :audience, numericality: { in: 0...3 }
validates :visibility, numericality: { in: 0...3 }
end

def visible_by?(level = 0)
audience <= level
end

def world_visible?
audience.zero?
visibilty.zero? && audience.zero?
end

def intranet_visible?
audience < 2
visibilty.zero? && audience < 2
end

def auth_visible?
audience < 3
visibilty.zero? && audience < 3
end

def owner_visible?
audience < 4
visibility != 2
end

def hidden?
audience > 3
visibility == 2
end

def visibility_label(v = visibility)
VISIBILITY_OPTIONS[v][:label]
end

def audience_label(v = audience)
AUDIENCE_OPTIONS[v][:label]
end
end
3 changes: 0 additions & 3 deletions app/models/profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,10 @@ class Profile < ApplicationRecord
show_nationality: false,
show_phone: true,
show_photo: false,
show_title: false,
force_lang: nil,
personal_web_url: nil,
nationality_en: nil,
nationality_fr: nil,
title_en: nil,
title_fr: nil
}.freeze

def self.new_with_defaults(sciper)
Expand Down
2 changes: 1 addition & 1 deletion app/views/awards/_award.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

json.extract! award, :id, :title_en, :title_fr, :issuer, :year,
:updated_at, :position, :audience, :visible
:updated_at, :position, :audience, :visibility

json.profile profile_url(award.profile, format: :json)
json.url award_url(award, format: :json)
2 changes: 1 addition & 1 deletion app/views/boxes/_box.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

json.extract! box, :id, :type, :subkind, :title_en, :title_fr, :show_title, :locked,
:updated_at, :position, :audience, :visible
:updated_at, :position, :audience, :visibility
json.profile profile_url(box.profile, format: :json)
1 change: 1 addition & 0 deletions app/views/educations/_education.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

json.extract! education, :id, :field_en, :field_fr, :title_en, :title_fr,
:year_begin, :year_end, :school, :director,
:audience, :visibility,
:created_at, :updated_at
json.profile profile_url(education.profile, format: :json)
json.url education_url(education, format: :json)
2 changes: 1 addition & 1 deletion app/views/experiences/_experience.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

json.extract! experience, :id, :title_en, :title_fr, :location, :year_begin, :year_end, :position, :created_at,
:updated_at, :position, :audience
:updated_at, :position, :audience, :visibility
json.profile profile_url(experience.profile, format: :json)
json.url experience_url(experience, format: :json)
2 changes: 1 addition & 1 deletion app/views/publications/_publication.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

json.extract! publication, :id, :title, :url, :authors, :year,
:audience, :created_at, :position, :updated_at
:audience, :visibility, :created_at, :position, :updated_at
json.profile profile_url(publication.profile, format: :json)
json.url publication_url(publication, format: :json)
2 changes: 1 addition & 1 deletion app/views/rich_text_boxes/_rich_text_box.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# frozen_string_literal: true

json.extract! box, :id, :created_at, :updated_at
json.extract! box, :id, :audience, :visibility, :created_at, :updated_at
json.url box_url(box, format: :json)
4 changes: 3 additions & 1 deletion app/views/shared/_item_actions.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
<%= link_to icon_text('action.delete', 'trash-2'), send("#{item.class.name.downcase}_path", item), class: "btn btn-secondary btn-sm", method: :delete, data: {turbo_stream: true, turbo_method:'delete', turbo_confirm: t('action.confirm')} %>
<%= link_to icon_text('action.edit', 'edit'), send("edit_#{item.class.name.downcase}_path", item), class: "btn btn-secondary btn-sm", data: {turbo_stream: true} %>
</p>
<!--
<span class="muted"><%= Award.human_attribute_name(:audience) %>: </span>
<%= render "shared/item_visibility", item: item %>
-->
<%= render "shared/item_visibility", item: item, extra_class: nil %>
Loading

0 comments on commit f60bf54

Please sign in to comment.