From 1a854007c43be71df0d3020dc6ce7d8d86cb0a40 Mon Sep 17 00:00:00 2001 From: Damir Sultanbekov Date: Wed, 24 Apr 2024 20:21:56 +0500 Subject: [PATCH] Replaced copyrighted column in Expressions table with enum intellectual_property. - Updated Manifestation CRUD pages - Updated TextAPI to accept array `intellectual_property_types` instead of `is_copyrighted` - Extracted common view code used to render intellectual property info with into a shared partial and reused it on several pages. - Updated Admin#missing_copyright action to render works with unknown intellectual property --- app/api/v1/entities/manifestation_index.rb | 5 ++- app/api/v1/texts_api.rb | 22 ++++++++-- app/chewy/manifestations_index.rb | 2 +- app/controllers/admin_controller.rb | 2 +- app/controllers/manifestation_controller.rb | 2 +- app/helpers/application_helper.rb | 18 +++++++- app/models/expression.rb | 5 +++ app/services/search_manifestations.rb | 7 +--- app/views/authors/_author_top.html.haml | 12 ++---- app/views/manifestation/_dict_entry_top.haml | 10 +---- app/views/manifestation/_dict_top.haml | 12 ++---- app/views/manifestation/_metadata.html.haml | 9 +--- .../manifestation/edit_metadata.html.haml | 11 ++--- app/views/manifestation/show.html.haml | 4 +- app/views/shared/_anth_panel.html.haml | 13 ++---- .../shared/_intellectual_property.html.haml | 6 +++ app/views/shared/_surprise_work.html.haml | 6 +-- config/locales/active_record.en.yml | 5 +++ config/locales/active_record.he.yml | 5 +++ config/locales/en.yml | 26 ++++++++++++ config/locales/he.yml | 42 +++++++++++++++---- .../20240424145657_change_copyrighted.rb | 17 ++++++++ db/schema.rb | 5 ++- spec/api/v1/text_api_spec.rb | 25 +++++++---- spec/controllers/admin_controller_spec.rb | 41 +++++++++++------- .../manifestations_controller_spec.rb | 5 ++- spec/factories/expressions.rb | 2 +- spec/factories/manifestations.rb | 4 +- spec/services/search_manifestations_spec.rb | 30 ++++--------- 29 files changed, 221 insertions(+), 132 deletions(-) create mode 100644 app/views/shared/_intellectual_property.html.haml create mode 100644 config/locales/active_record.en.yml create mode 100644 config/locales/active_record.he.yml create mode 100644 db/migrate/20240424145657_change_copyrighted.rb diff --git a/app/api/v1/entities/manifestation_index.rb b/app/api/v1/entities/manifestation_index.rb index b0b971d99..31685b1f5 100644 --- a/app/api/v1/entities/manifestation_index.rb +++ b/app/api/v1/entities/manifestation_index.rb @@ -20,7 +20,8 @@ class ManifestationIndex < Grape::Entity expose :orig_publication_date expose :author_gender, as: :author_genders, documentation: { values: ::Person.genders.keys, is_array: true } expose :translator_gender, as: :translator_genders, documentation: { values: ::Person.genders.keys, is_array: true } - expose :copyright_status, documentation: { type: 'Boolean' } + expose :intellectual_property, + documentation: { values: ::Expression.intellectual_properties.keys, is_array: true } expose :period, documentation: { values: Expression.periods.keys } expose :raw_creation_date expose :creation_date @@ -45,4 +46,4 @@ class ManifestationIndex < Grape::Entity end end end -end \ No newline at end of file +end diff --git a/app/api/v1/texts_api.rb b/app/api/v1/texts_api.rb index 5c5aa24bc..dc3f316ed 100644 --- a/app/api/v1/texts_api.rb +++ b/app/api/v1/texts_api.rb @@ -103,9 +103,10 @@ class V1::TextsAPI < V1::ApplicationApi type: [String], values: Expression.periods.keys, desc: 'specifies what section of the rough timeline of Hebrew literature an object belongs to.' - optional :is_copyrighted, - type: Boolean, - desc: 'limit search to copyrighted works or to non-copyrighted works' + optional :intellectual_property_types, + type: [String], + values: Expression.intellectual_properties.keys, + desc: 'limit search to works with selected intellectual property types' optional :author_genders, type: [String], values: Person.genders.keys optional :translator_genders, type: [String], values: Person.genders.keys optional :title, type: String, desc: "a substring to match against a text's title" @@ -140,7 +141,20 @@ class V1::TextsAPI < V1::ApplicationApi success V1::Entities::ManifestationsPage end post do - filters = params.slice(*%w(genres periods is_copyrighted author_genders translator_genders title author fulltext author_ids uploaded_between created_between published_between)) + filters = params.slice(*%w( + genres + periods + intellectual_property_types + author_genders + translator_genders + title + author + fulltext + author_ids + uploaded_between + created_between + published_between + )) orig_lang = params['original_language'] if orig_lang.present? diff --git a/app/chewy/manifestations_index.rb b/app/chewy/manifestations_index.rb index a541d152a..94ad79e6f 100644 --- a/app/chewy/manifestations_index.rb +++ b/app/chewy/manifestations_index.rb @@ -26,7 +26,7 @@ class ManifestationsIndex < Chewy::Index field :tags, type: 'keyword', value: ->{ approved_tags.map(&:name) } field :author_gender, value: ->(manifestation) {manifestation.author_gender }, type: 'keyword' field :translator_gender, value: ->(manifestation) {manifestation.translator_gender}, type: 'keyword' - field :copyright_status, value: ->(manifestation) {manifestation.copyright?}, type: 'keyword' # TODO: make non boolean + field :intellectual_property, value: ->(manifestation) {manifestation.expression.intellectual_property}, type: 'keyword' field :period, value: ->(manifestation) {manifestation.expression.period}, type: 'keyword' field :raw_creation_date, value: ->(manifestation) {manifestation.expression.work.date} field :creation_date, type: 'date', value: ->(manifestation) {normalize_date(manifestation.expression.work.date)} diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index c1c546e98..a6cd9d3d6 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -77,7 +77,7 @@ def missing_images def missing_copyright @authors = Person.where(public_domain: nil) - records = Manifestation.joins(:expression).where(expressions: {copyrighted: nil}) + records = Manifestation.joins(:expression).merge(Expression.intellectual_property_unknown) @total = records.count @mans = records.page(params[:page]).per(50) @page_title = t(:missing_copyright_report) diff --git a/app/controllers/manifestation_controller.rb b/app/controllers/manifestation_controller.rb index fbf7e50fa..bbbf1ed8d 100644 --- a/app/controllers/manifestation_controller.rb +++ b/app/controllers/manifestation_controller.rb @@ -489,7 +489,7 @@ def update @e.title = params[:etitle] @e.date = params[:edate] @e.comment = params[:ecomment] - @e.copyrighted = (params[:public_domain] == 'false' ? true : false) # field name semantics are flipped from param name, yeah + @e.intellectual_property = params[:intellectual_property] unless params[:add_person_e].blank? r = Realizer.new(expression_id: @e.id, person_id: params[:add_person_e], role: params[:role_e].to_i) r.save! diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a4761709a..a0fc46283 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -61,6 +61,11 @@ def textify_genre(genre) return I18n.t(genre) end + def textify_intellectual_property(value) + t(value, scope: 'intellectual_property') + end + + # TODO: remove def textify_copyright_status(copyrighted) copyrighted ? t(:by_permission) : t(:public_domain) end @@ -154,8 +159,17 @@ def translators_linked_string(m) return m.expression.translators.map{|x| "#{x.name}"}.join(', ') end - def copyright_glyph(is_copyright) - return is_copyright ? 'x' : 'm' # per /BY icons font/ben-yehuda/icons-reference.html + def intellectual_property_glyph(intellectual_property) + # per /BY icons font/ben-yehuda/icons-reference.html + case intellectual_property + when 'public_domain' + return 'm' + when 'copyrighted' + when 'by_permission' + return 'x' + else + return nil + end end def newsitem_glyph(item) # per icons-reference.html diff --git a/app/models/expression.rb b/app/models/expression.rb index c2dfbfaba..3f056ad3d 100644 --- a/app/models/expression.rb +++ b/app/models/expression.rb @@ -12,6 +12,11 @@ class Expression < ApplicationRecord has_many :tags, through: :taggings, class_name: 'Tag' has_paper_trail # for monitoring crowdsourced inputs + enum intellectual_property: { public_domain: 0, by_permission: 1, copyrighted: 2, orphan: 3, unknown: 100 }, + _prefix: true + + validates_presence_of :intellectual_property + def editors return realizers.includes(:person).where(role: Realizer.roles[:editor]).map{|x| x.person} end diff --git a/app/services/search_manifestations.rb b/app/services/search_manifestations.rb index 4bdd149a6..5c3e6b94e 100644 --- a/app/services/search_manifestations.rb +++ b/app/services/search_manifestations.rb @@ -19,12 +19,7 @@ def call(sort_by, sort_dir, filters) add_simple_filter(filter, :genre, filters['genres']) add_simple_filter(filter, :period, filters['periods']) - is_copyrighted = filters['is_copyrighted'] - - unless is_copyrighted.nil? - filter << { terms: { copyright_status: [is_copyrighted] } } - end - + add_simple_filter(filter, :intellectual_property, filters['intellectual_property_types']) add_simple_filter(filter, :author_gender, filters['author_genders']) add_simple_filter(filter, :translator_gender, filters['translator_genders']) add_simple_filter(filter, :author_ids, filters['author_ids']) diff --git a/app/views/authors/_author_top.html.haml b/app/views/authors/_author_top.html.haml index a2cb3a4b9..67dda6a6f 100644 --- a/app/views/authors/_author_top.html.haml +++ b/app/views/authors/_author_top.html.haml @@ -8,14 +8,8 @@ .author-page-top-years!= "(#{@author.life_years})" .author-top-second-line .author-page-top-rights - - if @author.public_domain - %span.by-icon-v02.copyright-icon> m - = textify_copyright_status(false) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_public_domain), 'data-content' => t(:public_domain_popover) - - else - %span.by-icon-v02.copyright-icon> x - = textify_copyright_status(true) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_permission), 'data-content' => t(:permission_popover) + = render partial: 'shared/intellectual_property', + locals: { intellectual_property: @author.public_domain ? :public_domain : :by_permission } .author-sort-area .author-page-top-sort-desktop.notyet = t(:sort_and_filter) @@ -73,4 +67,4 @@ $('.printbutton').click(function() { window.open("#{@print_url}",'_blank'); }); - }); \ No newline at end of file + }); diff --git a/app/views/manifestation/_dict_entry_top.haml b/app/views/manifestation/_dict_entry_top.haml index 5e6a50ef5..38b51f3be 100644 --- a/app/views/manifestation/_dict_entry_top.haml +++ b/app/views/manifestation/_dict_entry_top.haml @@ -20,14 +20,8 @@ - else = '?' .BYD-rights - - if @m.copyright? - %span.by-icon-v02.copyright-icon> x - = textify_copyright_status(true) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_permission), 'data-content' => t(:permission_popover) - - else - %span.by-icon-v02.copyright-icon> m - = textify_copyright_status(false) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_public_domain), 'data-content' => t(:public_domain_popover) + = render partial: 'shared/intellectual_property', + locals: { intellectual_property: @e.intellectual_property } .topNavEntryArea.topNavEntryAreaDesktop - unless @prev_entry.nil? .topNavEntry diff --git a/app/views/manifestation/_dict_top.haml b/app/views/manifestation/_dict_top.haml index 56816305d..3bcfec1a9 100644 --- a/app/views/manifestation/_dict_top.haml +++ b/app/views/manifestation/_dict_top.haml @@ -17,14 +17,8 @@ - else = '?' .BYD-rights - - if @m.copyright? - %span.by-icon-v02.copyright-icon> x - = textify_copyright_status(true) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_permission), 'data-content' => t(:permission_popover) - - else - %span.by-icon-v02.copyright-icon> m - = textify_copyright_status(false) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_public_domain), 'data-content' => t(:public_domain_popover) + = render partial: 'shared/intellectual_property', + locals: { intellectual_property: @e.intellectual_property } .author-sort-area.notyet#sort_filter_toggle{title: t(:toggle_filters_tt)} .author-page-top-sort-desktop %span.help= t(:filter)+' [?]' @@ -119,4 +113,4 @@ $('.toggle-button-no').toggle(); $('.toggle-button-yes').toggle(); }); - }); \ No newline at end of file + }); diff --git a/app/views/manifestation/_metadata.html.haml b/app/views/manifestation/_metadata.html.haml index dc40dd444..3d980f302 100644 --- a/app/views/manifestation/_metadata.html.haml +++ b/app/views/manifestation/_metadata.html.haml @@ -27,14 +27,7 @@ %div .metadata - - if @m.copyright? - %span.by-icon-v02> x - = textify_copyright_status(true) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_permission), 'data-content' => t(:permission_popover) - - else - %span.by-icon-v02> m - = textify_copyright_status(false) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_public_domain), 'data-content' => t(:public_domain_popover) + = render partial: 'shared/intellectual_property', locals: { intellectual_property: @e.intellectual_property } .metadata %span.by-icon-v02.internal-genre-icon>= glyph_for_genre(@w.genre) = textify_genre(@w.genre) diff --git a/app/views/manifestation/edit_metadata.html.haml b/app/views/manifestation/edit_metadata.html.haml index 697d770e3..738e63c83 100644 --- a/app/views/manifestation/edit_metadata.html.haml +++ b/app/views/manifestation/edit_metadata.html.haml @@ -49,12 +49,9 @@ %b= t(:comments)+': ' = text_area_tag :ecomment, @e.comment, rows: 4, cols: 40 %p - %h3= t(:copyright_status) - = radio_button_tag :public_domain, true, @e.copyrighted.nil? ? false : (not @e.copyrighted) - = label_tag t(:public_domain) - = radio_button_tag(:public_domain, false, @e.copyrighted.nil? ? false : @e.copyrighted) - = label_tag t(:by_permission) - / = textify_copyright_status(@e.copyrighted) # TODO: make editable + %h3= Expression.human_attribute_name(:intellectual_property) + - options = Expression.intellectual_properties.keys.map{ |code| [textify_intellectual_property(code), code] } + = select_tag :intellectual_property, options_for_select(options, @e.intellectual_property) = render partial: 'shared/associated_people', locals: { which: :expression, expression: @e, edit: true} %h2= t(:manifestation_details) @@ -95,4 +92,4 @@ = text_field_tag :link_description %p = submit_tag t(:save) -= link_to t(:back), action: :show, id: @m.id \ No newline at end of file += link_to t(:back), action: :show, id: @m.id diff --git a/app/views/manifestation/show.html.haml b/app/views/manifestation/show.html.haml index a34db0148..19111e44d 100644 --- a/app/views/manifestation/show.html.haml +++ b/app/views/manifestation/show.html.haml @@ -48,8 +48,8 @@ %b= t(:period) + ': ' = t(@e.period) %p - %b= t(:copyright_status) - = textify_copyright_status(@e.copyrighted) + %b #{Expression.human_attribute_name(:intellectual_property)}: + = textify_intellectual_property(@e.intellectual_property) %p %b= t(:language) + ': ' = textify_lang(@e.language) diff --git a/app/views/shared/_anth_panel.html.haml b/app/views/shared/_anth_panel.html.haml index dc5b64199..ab36569f4 100644 --- a/app/views/shared/_anth_panel.html.haml +++ b/app/views/shared/_anth_panel.html.haml @@ -93,14 +93,9 @@ %span{:style => "font-weight:bold"}= t(:page_count)+': ' %span= text.page_count %div - - if text.manifestation.copyright? - %span.by-icon-v02.copyright-icon> x - = textify_copyright_status(true) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_permission), 'data-content' => t(:permission_popover) - - else - %span.by-icon-v02.copyright-icon> m - = textify_copyright_status(false) - = link_to '[?]', '#', 'class' => 'help', 'data-toggle' => 'popover', 'data-trigger' => 'focus', title: t(:about_public_domain), 'data-content' => t(:public_domain_popover) + - intellectual_property = text.manifestation.expression.intellectual_property + = render partial: 'shared/intellectual_property', + locals: { intellectual_property: intellectual_property } .bottom-right-buttons #add_work_block{style: 'display: none'} .by-button-v02.by-button-secondary-v02#add_work_btn{title: t(:anth_add_work_tt)} @@ -285,4 +280,4 @@ // enable multi-select mode } }); - }); \ No newline at end of file + }); diff --git a/app/views/shared/_intellectual_property.html.haml b/app/views/shared/_intellectual_property.html.haml new file mode 100644 index 000000000..6ebbfa997 --- /dev/null +++ b/app/views/shared/_intellectual_property.html.haml @@ -0,0 +1,6 @@ +%span.by-icon-v02= intellectual_property_glyph(intellectual_property) += textify_intellectual_property(intellectual_property) += link_to '[?]', '#', + class: :help, + data: { toggle: :popover, trigger: :focus, content: t(".popover.#{intellectual_property}") }, + title: t(".about.#{intellectual_property}") diff --git a/app/views/shared/_surprise_work.html.haml b/app/views/shared/_surprise_work.html.haml index 146a8e76e..6e8938715 100644 --- a/app/views/shared/_surprise_work.html.haml +++ b/app/views/shared/_surprise_work.html.haml @@ -23,9 +23,9 @@ .row .col-md-6.col-sm-12 .metadata - .by-icon-v02.copyright-icon= copyright_glyph(manifestation.copyright?) - = textify_copyright_status(manifestation.copyright?) - %span.help{ 'data-toggle' => 'tooltip', title: manifestation.copyright? ? t(:permission_explain) : t(:pd_explain)}= '[?]' + .by-icon-v02.copyright-icon= intellectual_property_glyph(e.intellectual_property) + = textify_intellectual_property(e.intellectual_property) + %span.help{ data: { toggle: :tooltip }, title: t(".explanations.#{e.intellectual_property}")}= '[?]' - if e.translation .metadata %b= t(:orig_lang)+': ' diff --git a/config/locales/active_record.en.yml b/config/locales/active_record.en.yml new file mode 100644 index 000000000..82bb65856 --- /dev/null +++ b/config/locales/active_record.en.yml @@ -0,0 +1,5 @@ +en: + activerecord: + attributes: + expression: + intellectual_property: Type of intellectual property diff --git a/config/locales/active_record.he.yml b/config/locales/active_record.he.yml new file mode 100644 index 000000000..cbce66727 --- /dev/null +++ b/config/locales/active_record.he.yml @@ -0,0 +1,5 @@ +he: + activerecord: + attributes: + expression: + intellectual_property: Type of intellectual property diff --git a/config/locales/en.yml b/config/locales/en.yml index 56f1de28b..fa2cf173f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -8,6 +8,26 @@ en: next_page: Next page previous_page: Previous page first_page: First page + surprise_work: + explanations: + public_domain: not protected by intellectual property laws + by_permission: there is an explicit permission for publication from the owner + copyrighted: copyrighted + orphan: orphan + unknown: unknown + intellectual_property: + about: + public_domain: what does it means 'public domain'? + by_permission: what does it means 'by permission'? + copyrighted: what does it means 'copyrighted'? + orphan: what does it means 'orphan'? + unknown: what does it means 'unknown'? + popover: + public_domain: Copyright Law protects against unauthorized use of works for the duration of its validity (in Israel, seventy years from the end of the year of the creator's death). With the expiry of the rights, the creation becomes 'public domain', that is, the property of the public. This means that the work belongs to all of us, and we are all entitled to make any use of it, including commercial use, without the need to ask permission of anyone. + by_permission: Although the work is still copyrighted, the Ben־Yehuda Project has received *explicit permission to publish* The work in the Ben־Yehuda Project database, for the general public to read and research. Other uses (such as play, composition, or commercial performance) still *require express approval* from the rights holders. + copyrighted: TBD description for 'copyrighted' + orphan: TBD description for 'orphan' + unknown: TBD description for 'unknown' welcome: submit_contact: ziburit_failed: Control question failed @@ -24,3 +44,9 @@ en: ziburit_failed: Control question failed email_missing: Please provide an email address manifestation: + intellectual_property: + public_domain: public domain + by_permission: by permission + copyrighted: copyrighted + orphan: orphan + unknown: unknown diff --git a/config/locales/he.yml b/config/locales/he.yml index 044d06bf3..63d56f125 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -414,7 +414,6 @@ he: ready: מוכן photo: תמונה last_update: עדכון אחרון - copyright_status: מצב זכויות יוצרים basic_details: פרטים בסיסיים submit: שליחה logo: לוגו @@ -936,12 +935,6 @@ he: anth_text_deletion_p3: מתוך המקראה הנוכחית confirm_anth_text_deletion: אישור מחיקת הפריט מהמקראה maintenance: תחזוקה - public_domain: נחלת הכלל - about_public_domain: 'מה פירוש נחלת הכלל?' - public_domain_popover: "חוק זכויות יוצרים מגן מפני שימוש בלתי-מורשה ביצירות למשך תקופת תוקפו (בישראל, שבעים שנה מסוף שנת מות היוצר). עם פקוע הזכויות, הופכת היצירה 'נחלת הכלל', כלומר רכוש הציבור. פירוש הדבר שהיצירה שייכת לכולנו, וכולנו רשאים לעשות בה כל שימוש, לרבות שימוש מסחרי, מבלי צורך לבקש רשות מאיש." - about_permission: 'מה פירוש ברשות פרסום?' - permission_popover: "על אף שהיצירה עדיין מוגנת בזכויות יוצרים, פרויקט בן־יהודה קיבל *רשות מפורשת לפרסם* את היצירה במאגר היצירה של פרויקט בן־יהודה, לשימוש הקהל הרחב לקריאה ומחקר. שימושים אחרים (כגון המחזה, הלחנה, או ביצוע מסחרי) עדיין *טעונים אישור מפורש* מאת בעלי הזכויות." - by_permission: מוגש ברשות פרסום uploaded_images: נקלטו %{images_added} קבצים נוספים, ועכשיו יש ליצירה %{total} בסך הכל. add_image: הוספת תמונה add_all_images: הדבקת כל התמונות @@ -1235,8 +1228,6 @@ he: translator: מתרגם translator_f: מתרגמת translated_by: בתרגום - pd_explain: פגו זכויות היוצרים על יצירות אלו - permission_explain: התקבלה רשות מפורשת מבעלי הזכויות לפרסום היצירות about_the_author_on_the_blog: רשומות ביומן הרשת donate_title: תמיכה כספית בפרויקט donate_p1_html: כל עבודת ההקלדה, ההגהה והעריכה בפרויקט נעשית בהתנדבות וללא קבלת תמורה. עם זאת, אנו מזמינים שירותי פיתוח תוכנה, אפיון, ועיצוב מנשק משתמש מקבלנים, ולשם כך אנו מגייסים תרומות. @@ -1349,6 +1340,26 @@ he: next_page: לדף הבא previous_page: לדף הקודם first_page: לדף הראשון + surprise_work: + explanations: + public_domain: פגו זכויות היוצרים על יצירות אלו + by_permission: התקבלה רשות מפורשת מבעלי הזכויות לפרסום היצירות + copyrighted: copyrighted + orphan: orphan + unknown: unknown + intellectual_property: + about: + public_domain: מה פירוש נחלת הכלל? + by_permission: מה פירוש ברשות פרסום? + copyrighted: what does it means 'copyrighted'? + orphan: what does it means 'orphan'? + unknown: what does it means 'unknown'? + popover: + public_domain: חוק זכויות יוצרים מגן מפני שימוש בלתי-מורשה ביצירות למשך תקופת תוקפו (בישראל, שבעים שנה מסוף שנת מות היוצר). עם פקוע הזכויות, הופכת היצירה 'נחלת הכלל', כלומר רכוש הציבור. פירוש הדבר שהיצירה שייכת לכולנו, וכולנו רשאים לעשות בה כל שימוש, לרבות שימוש מסחרי, מבלי צורך לבקש רשות מאיש. + by_permission: על אף שהיצירה עדיין מוגנת בזכויות יוצרים, פרויקט בן־יהודה קיבל *רשות מפורשת לפרסם* את היצירה במאגר היצירה של פרויקט בן־יהודה, לשימוש הקהל הרחב לקריאה ומחקר. שימושים אחרים (כגון המחזה, הלחנה, או ביצוע מסחרי) עדיין *טעונים אישור מפורש* מאת בעלי הזכויות. + copyrighted: TBD description for 'copyrighted' + orphan: TBD description for 'orphan' + unknown: TBD description for 'unknown' welcome: submit_contact: ziburit_failed: לא השתכנענו שאינך רובוט. @@ -1365,3 +1376,16 @@ he: ziburit_failed: לא השתכנענו שאינך רובוט. email_missing: נא לציין כתובת דואל, כדי שנוכל להשיב לך. manifestation: + intellectual_property: + public_domain: נחלת הכלל + by_permission: מוגש ברשות פרסום + copyrighted: copyrighted + orphan: orphan + unknown: unknown + + copyright_status: מצב זכויות יוצרים + public_domain: נחלת הכלל + by_permission: מוגש ברשות פרסום + pd_explain: פגו זכויות היוצרים על יצירות אלו + permission_explain: התקבלה רשות מפורשת מבעלי הזכויות לפרסום היצירות + diff --git a/db/migrate/20240424145657_change_copyrighted.rb b/db/migrate/20240424145657_change_copyrighted.rb new file mode 100644 index 000000000..c74da6a95 --- /dev/null +++ b/db/migrate/20240424145657_change_copyrighted.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class ChangeCopyrighted < ActiveRecord::Migration[6.1] + def change + add_column :expressions, :intellectual_property, :integer + + execute <<~sql + update expressions set intellectual_property = case copyrighted when true then 1 when false then 0 else 100 end + sql + + change_column_null :expressions, :intellectual_property, false + + remove_column :expressions, :copyrighted + + add_index :expressions, :intellectual_property + end +end diff --git a/db/schema.rb b/db/schema.rb index 426861d1e..70f4007a7 100755 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2024_02_06_222123) do +ActiveRecord::Schema.define(version: 2024_04_24_145657) do create_table "aboutnesses", id: :integer, charset: "utf8mb4", collation: "utf8mb4_bin", force: :cascade do |t| t.integer "work_id" @@ -356,7 +356,6 @@ t.text "comment", size: :medium t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.boolean "copyrighted" t.date "copyright_expiration" t.boolean "translation" t.string "source_edition" @@ -364,6 +363,8 @@ t.string "normalized_pub_date" t.string "normalized_creation_date" t.integer "work_id", null: false + t.integer "intellectual_property", null: false + t.index ["intellectual_property"], name: "index_expressions_on_intellectual_property" t.index ["normalized_creation_date"], name: "index_expressions_on_normalized_creation_date" t.index ["normalized_pub_date"], name: "index_expressions_on_normalized_pub_date" t.index ["period"], name: "index_expressions_on_period" diff --git a/spec/api/v1/text_api_spec.rb b/spec/api/v1/text_api_spec.rb index 62f7fba38..f00c362a2 100644 --- a/spec/api/v1/text_api_spec.rb +++ b/spec/api/v1/text_api_spec.rb @@ -227,11 +227,12 @@ end end - context 'when filter by copyright is provided' do + context 'when filter by intellectual property types is provided' do let(:manifestations) { result = [] (1..60).each do |index| - e = create(:expression, copyrighted: index%10 == 0) + intellectual_property = %w(public_domain by_permission copyrighted unknown)[index%4] + e = create(:expression, intellectual_property: intellectual_property) result << create(:manifestation, impressions_count: Random.rand(100), expression: e) end result @@ -243,13 +244,21 @@ end end - let(:additional_params) { { is_copyrighted: true, sort_by: :popularity, sort_dir: :asc } } + let(:additional_params) do + { intellectual_property_types: %w(public_domain unknown), sort_by: :popularity, sort_dir: :asc } + end it 'returns only copyrighted works' do expect(subject).to eq 201 - expect(total_count).to eq 6 - expect(data.size).to eq 6 - expect(data_ids).to eq manifestations.select(&:copyright?).sort_by(&:impressions_count).map(&:id) + expect(total_count).to eq 30 + expect(data.size).to eq 25 + + matched = manifestations.select do |m| + m.expression.intellectual_property_public_domain? || m.expression.intellectual_property_unknown? + end + + expect(data_ids).to eq matched.sort_by(&:impressions_count).map(&:id)[0..24] + end end @@ -258,7 +267,7 @@ { 'genres' => %w(poetry), 'periods' => %w(revival), - 'is_copyrighted' => true, + 'intellectual_property_types' => %w(public_domain), 'author_genders' => %w(male), 'translator_genders' => %w(female), 'title' => 'Title', @@ -384,7 +393,7 @@ def assert_manifestation(json, manifestation, view, file_format, snippet) expect(md['orig_publication_date']).to eq normalize_date(expression.date).to_s expect(md['author_genders']).to eq manifestation.author_gender expect(md['translator_genders']).to eq manifestation.translator_gender - expect(md['copyright_status']).to eq manifestation.copyright? + expect(md['intellectual_property']).to eq manifestation.expression.intellectual_property expect(md['period']).to eq expression.period expect(md['raw_creation_date']).to eq work.date expect(md['creation_date']).to eq normalize_date(work.date).to_s diff --git a/spec/controllers/admin_controller_spec.rb b/spec/controllers/admin_controller_spec.rb index ead5df4f6..20c90dd04 100644 --- a/spec/controllers/admin_controller_spec.rb +++ b/spec/controllers/admin_controller_spec.rb @@ -56,24 +56,35 @@ describe '#incongruous_copyright' do include_context 'Admin user logged in' subject(:request) { get :incongruous_copyright } - let(:copyrighted_person) { create(:person, public_domain: false) } - let!(:public_domain_manifestation) { create(:manifestation, copyrighted: false) } - let!(:copyrighted_manifestation) { create(:manifestation, author: copyrighted_person, copyrighted: true) } - let!(:wrong_public_domain_manifestation_1) { create(:manifestation, author: copyrighted_person, copyrighted: false) } - let!(:wrong_public_domain_manifestation_2) { create(:manifestation, orig_lang: 'ru', translator: copyrighted_person, copyrighted: false) } - let!(:wrong_copyrighted_manifestation_1) { create(:manifestation, copyrighted: true) } - let!(:wrong_copyrighted_manifestation_2) { create(:manifestation, orig_lang: 'ru', copyrighted: true) } + let!(:public_domain_manifestation) do + create(:manifestation, intellectual_property: :public_domain) + end + let!(:by_permission_manifestation) do + create(:manifestation, author: copyrighted_person, intellectual_property: :by_permission) + end + let!(:wrong_public_domain_manifestation_1) do + create(:manifestation, author: copyrighted_person, intellectual_property: :public_domain) + end + let!(:wrong_public_domain_manifestation_2) do + create(:manifestation, orig_lang: 'ru', translator: copyrighted_person, intellectual_property: :public_domain) + end + let!(:wrong_by_permission_manifestation) do + create(:manifestation, intellectual_property: :by_permission) + end + let!(:wrong_copyrighted_manifestation) do + create(:manifestation, orig_lang: 'ru', intellectual_property: :copyrighted) + end - let(:wrong_manifestation_ids) { + let(:wrong_manifestation_ids) do [ wrong_public_domain_manifestation_1.id, wrong_public_domain_manifestation_2.id, - wrong_copyrighted_manifestation_1.id, - wrong_copyrighted_manifestation_2.id + wrong_by_permission_manifestation.id, + wrong_copyrighted_manifestation.id ] - } + end it 'renders successfully' do expect(request).to be_successful @@ -122,13 +133,13 @@ include_context 'Admin user logged in' subject(:request) { get :missing_copyright } - let!(:copyrighted_manifestation) { create(:manifestation, copyrighted: true) } - let!(:public_domain_manifestation) { create(:manifestation, copyrighted: false) } - let!(:missing_copyright_manifestation) { create(:manifestation, copyrighted: nil) } + let!(:by_permission_manifestation) { create(:manifestation, intellectual_property: :by_permission) } + let!(:public_domain_manifestation) { create(:manifestation, intellectual_property: :public_domain) } + let!(:unknown_manifestation) { create(:manifestation, intellectual_property: :unknown) } it 'shows records where copyright is nil' do expect(request).to be_successful - expect(assigns(:mans)).to eq [missing_copyright_manifestation] + expect(assigns(:mans)).to eq [unknown_manifestation] end end diff --git a/spec/controllers/manifestations_controller_spec.rb b/spec/controllers/manifestations_controller_spec.rb index 502aa0b57..f6a5da564 100644 --- a/spec/controllers/manifestations_controller_spec.rb +++ b/spec/controllers/manifestations_controller_spec.rb @@ -350,7 +350,8 @@ etitle: 'New Expression Title', genre: 'fables', wlang: 'ru', - primary: 'false' + primary: 'false', + intellectual_property: 'by_permission' } end @@ -359,7 +360,7 @@ expect(flash.notice).to eq I18n.t(:updated_successfully) manifestation.reload expect(manifestation).to have_attributes(title: 'New Manifestation Title') - expect(expression).to have_attributes(title: 'New Expression Title') + expect(expression).to have_attributes(title: 'New Expression Title', intellectual_property: 'by_permission') expect(work).to have_attributes(title: 'New Work Title', orig_lang: 'ru', genre: 'fables', primary: false) end end diff --git a/spec/factories/expressions.rb b/spec/factories/expressions.rb index 674745769..53fa8dfc8 100644 --- a/spec/factories/expressions.rb +++ b/spec/factories/expressions.rb @@ -16,7 +16,7 @@ date { '2 ביוני 1960' } language { 'he' } comment { "Comment for #{expression_name}" } - copyrighted { false } + intellectual_property { :public_domain } copyright_expiration { nil } translation { orig_lang != language } source_edition {} diff --git a/spec/factories/manifestations.rb b/spec/factories/manifestations.rb index 18ff01403..1ddfb133e 100644 --- a/spec/factories/manifestations.rb +++ b/spec/factories/manifestations.rb @@ -10,7 +10,7 @@ translator { orig_lang != language ? create(:person) : nil } editor { nil } illustrator { nil } - copyrighted { false } + intellectual_property { :public_domain } expression_title { title } work_title { title } primary { true } @@ -38,7 +38,7 @@ orig_lang: orig_lang, genre: genre, period: period, - copyrighted: copyrighted, + intellectual_property: intellectual_property, primary: primary ) end diff --git a/spec/services/search_manifestations_spec.rb b/spec/services/search_manifestations_spec.rb index 2d4e31eee..44bc5cf28 100644 --- a/spec/services/search_manifestations_spec.rb +++ b/spec/services/search_manifestations_spec.rb @@ -38,7 +38,7 @@ genre = %w(poetry prose drama fables article)[index % 5] period = %w(ancient medieval enlightenment revival modern)[index % 5] - copyrighted = index % 10 == 0 + intellectual_property = %w(public_domain copyrighted by_permission unknown)[index % 4] realizers = [] @@ -58,7 +58,7 @@ :expression, period: period, genre: genre, - copyrighted: copyrighted, + intellectual_property: intellectual_property, realizers: realizers, date: published_at.strftime('%d.%m.%Y'), work: work @@ -136,26 +136,14 @@ end end - describe 'by copyright' do - let(:filter) { { 'is_copyrighted' => is_copyrighted } } + describe 'by intellectual property types' do + let(:types) { %w(public_domain unknown) } + let(:filter) { { 'intellectual_property_types' => types } } - context 'when copyrighted texts requested' do - let(:is_copyrighted) { true } - it 'returns all copyrighted texts' do - expect(subject.count).to eq 20 - subject.limit(REC_COUNT).each do |rec| - expect(rec.copyright_status).to be_truthy - end - end - end - - context 'when not copyrighted texts requested' do - let(:is_copyrighted) { false } - it 'returns all not copyrighted texts' do - expect(subject.count).to eq 180 - subject.limit(REC_COUNT).each do |rec| - expect(rec.copyright_status).to be_falsey - end + it 'returns all works with given intellectual property types' do + expect(subject.count).to eq 100 + subject.limit(REC_COUNT).each do |rec| + expect(types).to include(rec.intellectual_property) end end end