Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to set a license for each track separately #1197

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8e24cbe
Add license_code column to assets.
Manfred Apr 11, 2022
75dd5b6
Update schema.
Manfred Apr 11, 2022
8e30a4a
Add a model to handle license codes.
Manfred Apr 11, 2022
f64bd5f
Add a validator for license codes.
Manfred Apr 11, 2022
d93e05d
Localize license and license code related text.
Manfred Apr 11, 2022
72748c1
Validate Asset license code and return license.
Manfred Apr 11, 2022
17f2201
Allow users to select and update license code for asset.
Manfred Apr 11, 2022
7fff817
Show asset license icons with track.
Manfred Apr 11, 2022
f014ea1
Expand license options when toggle is activated.
Manfred Apr 11, 2022
7379d05
Style license icons and license options.
Manfred Apr 11, 2022
64d58a3
Add title to asset license link.
Manfred Apr 11, 2022
27bee16
Start 2022 changes to assets#show
ofsound May 3, 2022
f0dea7d
Round two of changes to the new track content view
ofsound May 11, 2022
f7e8a4e
Start in on and make a mess of track_edit
ofsound May 11, 2022
229af0c
Another round on track_edit
ofsound May 11, 2022
4dd0b38
Start the SVG replacement for the radio inputs
ofsound May 12, 2022
bc3036d
Refactor the CSS
ofsound May 12, 2022
90d18c8
Details and clean-up on edit and post
ofsound May 12, 2022
004c944
Some alignment adjusments
ofsound May 12, 2022
74ac46e
Hit some color theming, button adjustment
ofsound May 17, 2022
3de855b
Add the "BY-NC" labels throughout
ofsound May 17, 2022
c9480cd
Make some mobile adjustments
ofsound May 17, 2022
a0adf90
Couple more responsive overflow styles
ofsound May 17, 2022
9730ead
Fix typo
ofsound May 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,22 @@
}
}
}
.license {
a {
width: 106px;
margin-right: 8px;
svg {
height: 24px;
margin-left: 6px;
margin-top: 1px;
top: 0;
fill: $track-content-license-text;
circle {
fill: none;
}
}
}
}
}
}
.track_edit {
Expand Down Expand Up @@ -265,6 +281,48 @@
textarea#asset_credits {
display: none;
}
.collapsed {
> a {
display: inline-block;
margin-top: 6px;
}
.option {
&.selected { display: block; }
display: none;
}
}
.expanded {
> a {
display: none;
}
.option {
display: block;
}
}
.options {
margin-bottom: 24px;
* {
margin: 0;
padding: 0;
}
div + div {
margin-top: 6px;
}
label {
color: $forms-heading-text;
margin-bottom: 0 !important;
}
p.help {
color: $forms-hint-text;
font-size: 90%;
a {
color: $forms-hint-background;
}
a:hover {
color: $forms-hint-text;
}
}
}
.track_edit_bottom {
.new_version {
input[type="file"] {
Expand Down
2 changes: 2 additions & 0 deletions app/assets/stylesheets/themes/dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ $track-content-track-text: $grey50;
$track-content-artist-text: $white;
$track-content-description-text: $grey400;

$track-content-license-text: $grey1000;

// track_player.scss
$waveform-unplayed-background: $grey900;
$waveform-played-background: $grey100;
Expand Down
2 changes: 2 additions & 0 deletions app/assets/stylesheets/themes/white.scss
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ $track-content-track-text: $grey1000;
$track-content-artist-text: $black;
$track-content-description-text: $grey900;

$track-content-license-text: $grey200;

// track_player.scss
$waveform-unplayed-background: $grey400;
$waveform-played-background: $grey1000;
Expand Down
1 change: 1 addition & 0 deletions app/controllers/assets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def asset_params
:description,
:name,
:title,
:license_code,
:user,
:user_id,
:youtube_embed
Expand Down
7 changes: 7 additions & 0 deletions app/javascript/controllers/license_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Controller } from "@hotwired/stimulus"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parsing error: [BABEL]: Cannot find module 'shakapacker'
Require stack:

  • /code/config/webpack/preset.js
  • /usr/local/node_modules/@babel/core/lib/config/files/module-types.js
  • /usr/local/node_modules/@babel/core/lib/config/files/configuration.js
  • /usr/local/node_modules/@babel/core/lib/config/files/index.js
  • /usr/local/node_modules/@babel/core/lib/index.js
  • /usr/local/node_modules/@babel/eslint-parser/lib/worker/babel-core.cjs
  • /usr/local/node_modules/@babel/eslint-parser/lib/worker/handle-message.cjs
  • /usr/local/node_modules/@babel/eslint-parser/lib/client.cjs
  • /usr/local/node_modules/@babel/eslint-parser/lib/index.cjs
  • /usr/local/node_modules/eslint/lib/cli-engine/config-array-factory.js
  • /usr/src/app/lib/eslint6-patch.js
  • /usr/src/app/lib/eslint.js
  • /usr/src/app/bin/eslint.js (While processing: /code/config/webpack/preset.js)


export default class extends Controller {
expand() {
this.element.classList.add('expanded')
}
}
7 changes: 7 additions & 0 deletions app/models/asset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class Asset < ApplicationRecord
content_type: %w[audio/mpeg audio/mp3 audio/x-mp3],
byte_size: { less_than: 60.megabytes }
}
validates :license_code, license_code: true

include Slugs
has_slug(
Expand Down Expand Up @@ -206,6 +207,12 @@ def download_location
Storage::Location.new(audio_file, signed: true)
end

def license
return nil unless License.supported?(license_code)

License.new(license_code)
end

def self.destroy_deleted_accounts_older_than_30_days
Asset.destroyable.find_each do |asset|
AssetCommand.new(asset).destroy_with_relations
Expand Down
131 changes: 131 additions & 0 deletions app/models/license.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# frozen_string_literal: true

# Proxies string values for a license to produce useful data for the website.
class License
CURRENT_VERSION = '4.0'
VERSION_RE = /\A[\d.]+\Z/.freeze
# rubocop:disable Layout/LineLength
ICONS = {
cc: '<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><circle cx="32.3" cy="32" r="28.8" fill="#fff"/><path d="M32 0a31.2 31.2 0 0 1 29.7 19.7 32.6 32.6 0 0 1 0 24.6A32.9 32.9 0 0 1 32 64a31.1 31.1 0 0 1-22.6-9.5A31.9 31.9 0 0 1 31.9 0zm0 5.8c-7.3 0-13.4 2.5-18.4 7.6A27.5 27.5 0 0 0 7.8 22a25.2 25.2 0 0 0 0 20 26.5 26.5 0 0 0 43 8.3c5-4.8 7.4-11 7.4-18.3a26.3 26.3 0 0 0-7.6-18.5 25.3 25.3 0 0 0-18.5-7.7zm-.3 20.9l-4.3 2.2c-.5-1-1-1.6-1.7-2-.7-.4-1.3-.6-1.9-.6-2.8 0-4.3 2-4.3 5.7 0 1.7.4 3 1.1 4.1.7 1 1.8 1.6 3.2 1.6 1.9 0 3.2-1 4-2.8l4 2a9.4 9.4 0 0 1-8.5 5c-2.8 0-5.2-.8-6.9-2.6a9.9 9.9 0 0 1-2.6-7.3c0-3 .9-5.5 2.6-7.3a9 9 0 0 1 6.7-2.6c4 0 6.8 1.5 8.6 4.6zm18.4 0L46 28.9c-.5-1-1-1.6-1.7-2-.7-.4-1.3-.6-2-.6-2.8 0-4.2 2-4.2 5.7 0 1.7.4 3 1 4.1.8 1 1.9 1.6 3.3 1.6 1.8 0 3.2-1 4-2.8l4 2c-1 1.6-2.1 2.8-3.6 3.7a9.2 9.2 0 0 1-4.9 1.3c-2.9 0-5.2-.8-7-2.6a10 10 0 0 1-2.5-7.3c0-3 .9-5.5 2.6-7.3a9 9 0 0 1 6.8-2.6c4 0 6.7 1.5 8.4 4.6z" fill-rule="nonzero"/></svg>',
by: '<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><circle cx="32.1" cy="32.3" r="28.3" fill="#fff"/><path d="M32 0c9 0 16.5 3 22.7 9.3A31 31 0 0 1 64 32c0 9-3 16.5-9.1 22.5a31.6 31.6 0 0 1-23 9.5 31 31 0 0 1-22.5-9.4A30.8 30.8 0 0 1 0 32c0-8.8 3.1-16.3 9.4-22.7A30.6 30.6 0 0 1 32 0zm0 5.8a25 25 0 0 0-18.4 7.6 25.7 25.7 0 0 0 0 37A25.3 25.3 0 0 0 32 58.2c7 0 13.3-2.6 18.6-7.9 5-4.8 7.5-11 7.5-18.3 0-7.3-2.5-13.5-7.6-18.6A25.2 25.2 0 0 0 32 5.8zM40.7 24v13H37v15.6H27V37h-3.6v-13c0-.6.2-1.1.6-1.5a2 2 0 0 1 1.4-.6h13.2c.5 0 1 .2 1.4.6.4.4.6.9.6 1.5zm-13-8.3c0-3 1.4-4.5 4.4-4.5 3 0 4.5 1.5 4.5 4.5S35 20.3 32 20.3s-4.5-1.5-4.5-4.5z" fill-rule="nonzero"/></svg>',
nc: '<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><circle cx="32" cy="32.2" r="29.5" fill="#fff"/><path d="M32 0c9 0 16.5 3 22.7 9.3A30.8 30.8 0 0 1 64 32c0 9-3 16.5-9.1 22.5a31.6 31.6 0 0 1-45.5 0A30.7 30.7 0 0 1 0 32c0-8.8 3.1-16.3 9.4-22.7A30.6 30.6 0 0 1 32 0zM7.1 23.4c-1 2.6-1.4 5.5-1.4 8.6 0 7 2.6 13.2 7.7 18.4a25.5 25.5 0 0 0 18.6 7.7c7.2 0 13.4-2.6 18.6-7.8 1.9-1.8 3.3-3.7 4.4-5.6l-12-5.4c-.5 2-1.5 3.7-3.1 5-1.7 1.2-3.6 2-5.8 2.2v4.9h-3.7v-5c-3.5 0-6.8-1.3-9.7-3.8l4.4-4.4c2 2 4.5 2.9 7.1 2.9 1.1 0 2-.3 2.9-.8.8-.5 1.1-1.3 1.1-2.4 0-.8-.2-1.5-.8-2l-3.1-1.3-3.8-1.7-5-2.2-16.4-7.3zM32.1 5.7c-7.3 0-13.5 2.6-18.5 7.7a30.6 30.6 0 0 0-3.5 4.3l12.2 5.5c.5-1.7 1.5-3 3-4s3.2-1.6 5.2-1.7v-5h3.7v5c3 .1 5.6 1.1 8 3l-4.1 4.2a9.5 9.5 0 0 0-5.5-1.8 6 6 0 0 0-2.7.5c-.8.4-1.2 1-1.2 2l.3.8 4 1.8 2.9 1.3 5.1 2.2L57.4 39c.6-2.3.8-4.6.8-6.9a25 25 0 0 0-7.6-18.6A25 25 0 0 0 32 5.7z" fill-rule="nonzero"/></svg>',
nd: '<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><circle cx="32.1" cy="31.8" r="29" fill="#fff"/><path d="M32 0a31 31 0 0 1 22.7 9.3A30.8 30.8 0 0 1 64 32c0 9-3 16.5-9.1 22.5-6.5 6.3-14.1 9.5-23 9.5a31 31 0 0 1-22.5-9.4A30.8 30.8 0 0 1 0 32c0-8.7 3.1-16.3 9.4-22.7A30.7 30.7 0 0 1 32 0zm0 5.8c-7.2 0-13.4 2.5-18.4 7.7a25.6 25.6 0 0 0 0 36.9A25.3 25.3 0 0 0 32 58.2c7 0 13.3-2.6 18.6-7.9 5-4.8 7.5-11 7.5-18.3a25 25 0 0 0-7.6-18.5A25 25 0 0 0 32 5.8zm12.1 18.7v5.4H21v-5.4H44zm0 10.2v5.5H21v-5.5H44z" fill-rule="nonzero"/></svg>',
sa: '<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><circle cx="31.4" cy="32.1" r="29.1" fill="#fff"/><path d="M32 0a31 31 0 0 1 22.7 9.3A30.8 30.8 0 0 1 64 32c0 9-3 16.5-9.1 22.5-6.5 6.3-14.1 9.5-23 9.5a31 31 0 0 1-22.5-9.4A30.8 30.8 0 0 1 0 32c0-8.7 3.1-16.3 9.4-22.7A30.7 30.7 0 0 1 32 0zm0 5.8c-7.2 0-13.4 2.5-18.4 7.7a25.6 25.6 0 0 0 0 36.9A25.3 25.3 0 0 0 32 58.2c7 0 13.3-2.6 18.6-7.9 5-4.8 7.5-11 7.5-18.3a25 25 0 0 0-7.6-18.5A25 25 0 0 0 32 5.8zM17.9 27.5c.6-4 2.2-7 4.7-9.1a14 14 0 0 1 9.3-3.3c5 0 9 1.7 12 4.9s4.5 7.4 4.5 12.5c0 4.9-1.6 9-4.6 12.2-3.1 3.3-7.1 4.9-12 4.9a13.8 13.8 0 0 1-14.1-12.5h8c.2 3.9 2.5 5.8 7 5.8 2.3 0 4-1 5.5-2.9 1.3-2 2-4.5 2-7.8 0-3.4-.6-6-1.9-7.7a6.3 6.3 0 0 0-5.4-2.7c-4.3 0-6.7 2-7.2 5.7h2.3l-6.3 6.3-6.3-6.3h2.5z" fill-rule="nonzero"/></svg>',
'all-rights-reserved': '<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><circle cx="32.1" cy="32.3" r="28.3" fill="#fff"/><path d="M32 0c9 0 16.5 3 22.7 9.3A31 31 0 0 1 64 32c0 9-3 16.5-9.1 22.5a31.6 31.6 0 0 1-23 9.5 31 31 0 0 1-22.5-9.4A30.8 30.8 0 0 1 0 32c0-8.8 3.1-16.3 9.4-22.7A30.6 30.6 0 0 1 32 0zm0 5.8a25 25 0 0 0-18.4 7.6 25.7 25.7 0 0 0 0 37A25.3 25.3 0 0 0 32 58.2c7 0 13.3-2.6 18.6-7.9 5-4.8 7.5-11 7.5-18.3 0-7.3-2.5-13.5-7.6-18.6A25.2 25.2 0 0 0 32 5.8z" fill-rule="nonzero"/><path d="M47.6 37.4h-6.4a6.6 6.6 0 0 1-2.5 4.5 8.6 8.6 0 0 1-5.4 1.6c-1.4 0-2.7-.3-3.9-.9a9.1 9.1 0 0 1-2.9-2.4c-.8-1-1.4-2.2-1.9-3.6-.4-1.4-.6-2.9-.6-4.4 0-3.3.7-6 2.3-8a8 8 0 0 1 6.8-3.1c2 0 3.8.5 5.3 1.5a7 7 0 0 1 2.8 4.4h6.1c-.2-2-.8-3.8-1.6-5.3a12.8 12.8 0 0 0-7.4-6.1 17.6 17.6 0 0 0-12.2.6 15.2 15.2 0 0 0-8.5 9.2 20.9 20.9 0 0 0 0 13.9 15.6 15.6 0 0 0 8.7 9.2 17.4 17.4 0 0 0 12 .5 13.5 13.5 0 0 0 7.5-6.4c.9-1.5 1.5-3.3 1.8-5.2z" fill-rule="nonzero"/></svg>'
}.freeze
# rubocop:enable Layout/LineLength

attr_reader :name_with_version

def initialize(name_with_version)
@name_with_version = name_with_version
end

def name
name_with_version.split('/', 2)[0]
end

def version
name_with_version.split('/', 2)[1]
end

def jurisdiction
'international'
end

def current?
if %w[all-rights-reserved defined-in-content].include?(name)
true
else
self.class.parse_version(version) == self.class.parse_version(CURRENT_VERSION)
end
end

def current_version
return self if current?

License.new("#{name}/#{CURRENT_VERSION}")
end

def supported?
case name_with_version
when 'all-rights-reserved'
true
else
name.present? && !!VERSION_RE.match(version.to_s)
end
end

def label
I18n.t("licenses.label.#{name}", version: '', jurisdiction: '').strip
end

def full_label
I18n.t(
"licenses.label.#{name}",
version: version,
jurisdiction: I18n.t("licenses.jurisdiction.#{jurisdiction}")
).strip
end
alias to_s full_label

def short_label
if version.present?
"#{name.upcase} #{version}"
end
end

def help
I18n.t("licenses.help.#{name}")
end

def url
return unless version.present?

"https://creativecommons.org/licenses/#{name_with_version}/deed.en"
end

def icons
if version.present?
(['cc'] + name.split('-')).map { |code| ICONS[code.to_sym] }.join.html_safe
else
ICONS[name.to_sym].html_safe
end
end

def ==(other)
other.is_a?(License) && name_with_version == other.name_with_version
end

def self.supported?(name_with_version)
new(name_with_version).supported?
end

def self.find(name)
all.find do |license|
license.name == name
end
end

def self.default
License.new('all-rights-reserved')
end

def self.others
codes.map do |id|
License.new("#{id}/#{CURRENT_VERSION}")
end
end

def self.all
[default] + others
end

def self.codes
%w[by by-nc by-nc-nd by-nc-sa by-nd by-sa]
end

def self.parse_version(version)
version.to_s.split('.').map(&:to_i)
end
end
12 changes: 12 additions & 0 deletions app/validators/license_code_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

# Uses the License model to validate a license code value and make sure it's supported.
#
# validates :license_code, license_code: true
class LicenseCodeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.present? && License.new(value).supported?

record.errors.add(attribute, :invalid_license_code, license_code: value)
end
end
16 changes: 16 additions & 0 deletions app/views/assets/_edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@
<%= f.text_area :description, placeholder: "Tell us a story...", id: "description_#{asset.id}" %>
<%= f.text_area :credits, placeholder: "Credits for this track" %>

<div class="options collapsed" data-controller="license">
<% License.all.each_with_index do |license, index| %>
<%= tag.div(value: license.name_with_version, class: (f.object.license_code == license.name_with_version) ? 'option selected' : 'option') do %>
<%= f.label :license_code do %>
<%= f.radio_button :license_code, license.name_with_version %>
<%= license.label %>
<% end %>
<p class="help">
<%= license.help %>
<%= link_to 'Details', license.url, target: '_blank' if license.url.present? %>
</p>
<% end %>
<% end %>
<%= tag.a('Choose another license…', data: { 'action' => 'license#expand'}) %>
</div>

<div class="track_edit_bottom">
<% if @single_track_page %>
<%= link_to 'Upload a new version of this track',"#new_version_#{asset.object_id}", class: 'slide_open_href'%>
Expand Down
6 changes: 6 additions & 0 deletions app/views/shared/_asset.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@
</div>
<% end %>

<div class="license">
<%= tag.a(href: @asset.license.url) do %>
<%= @asset.license.icons %>
<% end %>
</div>

<div class="edit_links">
<% if authorized? %>
<%= link_to("Edit", edit_user_track_path(@user, @asset), class: "edit_link") %>
Expand Down
27 changes: 25 additions & 2 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,37 @@ en:
attributes:
account_request:
entity_type: "What you do:"

errors:
messages:
not_attached: must be attached
byte_size_too_small: must be greater than %{greater_than_human_size}
byte_size_too_large: must be less than %{less_than_human_size}
invalid_content_type: does not look the right file type
attributes:
license_code:
invalid_license_code: must be supported
authlogic:
error_messages:
no_authentication_details: Login and password need to be filled out
login_not_found: not found (It should be the same as your profile url)
login_not_found: not found (It should be the same as your profile url)
licenses:
help:
all-rights-reserved: You reserve all rights provided by copyright law.
by: Anyone is free to share and adapt your video.
by-nc: Anyone is free to share and adapt your video, but not for commercial purposes.
by-nc-nd: Your video can be shared freely, but not for commercial purposes.
by-nc-sa: Anyone is free to share and adapt your video, but not for commercial purposes, and only under the same license.
by-nd: Your video can be shared freely.
by-sa: Anyone is free to share and adapt your video, but only under the same license.
defined-in-content: For when the license information shown in the video is different from the licenses listed above.
jurisdiction:
international: International
label:
all-rights-reserved: All rights reserved
by: Attribution %{version} %{jurisdiction}
by-nc: Attribution-Noncommercial %{version} %{jurisdiction}
by-nc-nd: Attribution-Noncommercial-No Derivative Works %{version} %{jurisdiction}
by-nc-sa: Attribution-Noncommercial-Share Alike %{version} %{jurisdiction}
by-nd: Attribution-No Derivative Works %{version} %{jurisdiction}
by-sa: Attribution-Share Alike %{version} %{jurisdiction}
defined-in-content: As defined in content
5 changes: 5 additions & 0 deletions db/migrate/20220411170613_add_license_code_to_assets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddLicenseCodeToAssets < ActiveRecord::Migration[7.0]
def change
add_column :assets, :license_code, :string, default: 'all-rights-reserved'
end
end
Loading