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

Updating terms of service with data retention policy (SCP-5792) #2195

Merged
merged 7 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class ApplicationController < ActionController::Base
before_action :get_download_quota
before_action :get_deployment_notification
before_action :set_selected_branding_group
before_action :check_tos_acceptance
# allow users to view privacy policy even if they haven't accepted the ToS yet
before_action :check_tos_acceptance, except: :privacy_policy
before_action :set_ab_test_assignments

rescue_from ActionController::InvalidAuthenticityToken, with: :invalid_csrf
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/profiles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ def update_firecloud_profile
end
end

def accept_tos; end
def accept_tos
@previous_acceptance = TosAcceptance.where(
email: @user.email, :version.ne => TosAcceptance::CURRENT_VERSION
).order_by(&:version).last
end

def record_tos_action
user_accepted = tos_params[:action] == 'accept'
Expand Down
21 changes: 21 additions & 0 deletions app/models/study.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Study
ASSOCIATED_MODEL_DISPLAY_METHOD = %w(name url_safe_name bucket_id firecloud_project firecloud_workspace workspace_url google_bucket_url gs_url)
OUTPUT_ASSOCIATION_ATTRIBUTE = %w(id)

MAX_EMBARGO = 2.years.freeze
###
#
# SETTINGS, ASSOCIATIONS AND SCOPES
Expand Down Expand Up @@ -744,6 +745,7 @@ def author
validates_presence_of :firecloud_project, :firecloud_workspace
validates_uniqueness_of :external_identifier, allow_blank: true
validates :cell_count, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validate :enforce_embargo_max_length

# callbacks
before_validation :set_url_safe_name
Expand Down Expand Up @@ -1678,6 +1680,17 @@ def verify_remote_file(remotes:, file_location:)
remotes.any? ? remotes.detect {|remote| remote.name == file_location} : ApplicationController.firecloud_client.execute_gcloud_method(:get_workspace_file, 0, self.bucket_id, file_location)
end

# get the max date for a data embargo
def max_embargo
start_date = persisted? ? created_at.to_date : Date.today
start_date + MAX_EMBARGO
end

# get the max embargo duration as text, e.g. '2 years'
def self.max_embargo_text
MAX_EMBARGO.parts.map { |k, v| "#{v} #{k}" }.join(', ')
end

###
#
# FIRECLOUD FILE METHODS
Expand Down Expand Up @@ -1870,6 +1883,14 @@ def set_data_dir
#
###

def enforce_embargo_max_length
return true if embargo.blank? || !public

unless embargo <= created_at + MAX_EMBARGO
errors.add(:embargo, "cannot be longer than two years from date of creation (#{created_at.to_date.strftime('%m/%d/%Y')}) for public studies")
end
end

# automatically create a FireCloud workspace on study creation after validating name & url_safe_name
# will raise validation errors if creation, bucket or ACL assignment fail for any reason and deletes workspace on validation fail
def initialize_with_new_workspace
Expand Down
2 changes: 1 addition & 1 deletion app/models/tos_acceptance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class TosAcceptance
include Mongoid::Document
include Mongoid::Timestamps

CURRENT_VERSION = Date.parse('2018-08-29') # current revision of ToS
CURRENT_VERSION = Date.parse('2025-01-15') # current revision of ToS

field :email, type: String
field :version, type: Date, default: CURRENT_VERSION
Expand Down
8 changes: 8 additions & 0 deletions app/views/profiles/accept_tos.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<h1 id="tos-title">Terms of service, revised [<%= TosAcceptance.current_version %>]</h1>
<div id="tos-content">
<% if @previous_acceptance %>
<div class="bs-callout bs-callout-primary">
<p>
Our terms have updated since the last version on <%= @previous_acceptance.version %>. Please review carefully
the terms in their entirety by scrolling to the bottom of the page.
</p>
</div>
<% end %>
<%= render :partial => '/site/tos_content' %>
</div>
<%= form_for :tos, url: record_tos_action_path, html: {class: 'form', id: 'tos-form'} do |f| %>
Expand Down
7 changes: 4 additions & 3 deletions app/views/site/_study_settings_general.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
<div class="form-group row">
<div class="col-md-4">
<%= f.label :embargo, 'Data release date' %>&nbsp;
<span class='fas fa-question-circle' data-toggle='tooltip'
<span class='fas fa-question-circle' data-toggle='tooltip' data-placement='right'
title='Setting a data release date will prevent downloads for everyone except study owners & shared users,
and will expire at 12AM on the date specified (leave blank to allow downloads)' data-placement='right'>
and will expire at 12AM on the date specified (leave blank to allow downloads). This has a maximum length of
<%= Study.max_embargo_text %> from date of creation for public studies.'>
</span><br />
<%= f.date_field :embargo, class: 'form-control' %>
<%= f.date_field :embargo, class: 'form-control', max: f.object.max_embargo %>
</div>
<div class="col-md-4">
<%= f.label :public %><br />
Expand Down
24 changes: 23 additions & 1 deletion app/views/site/_tos_content.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,30 @@
or confidential data unless appropriate consents and/or approvals have been obtained.</li>
<li>Assure the owner and individuals who have sharing access to a study agree to having their emails associated publicly
with the study or have sharing access removed before the study is public.</li>

</ul>
<h3>Data Retention Policy</h3>
<p>All users creating a new study are permitted to upload and host data on SCP free of charge by selecting the "Default"
Terra billing project. Any study created in that project will be subject to the following data retention policy.
Any study created in a user-controlled Terra billing project is exempt.</p>
<h4>Storage Amount</h4>
<p>
There is a soft cap of 200 GB total for all uploads to an individual study. Any data in excess of this cap may be
subject to removal unless approved at the discretion SCP admins. A notification will be sent to the study owner 30
days prior to any data removal, and the study owner may elect to download their data prior to removal.
</p>
<h4>Public Studies</h4>
<p>Any study marked as "public" that provides visualizations and/or downloadable data files can be stored indefinitely
provided it remains public and accessible. We ask that study owners not upload intermediate analysis files unless they
are also made available for download.</p>
<h4>Private Studies</h4>
<p>Any study that is not publicly accessible may be stored for a term of up to one year from the data of creation.
After this term expires, such studies will be candidates for removal. Study owners will be notified prior to any
removal and given a period of 30 days in which to convert their study to public or download their data. After this
period expires, any remaining private studies are subject to removal at the discretion of SCP admins.</p>
<h3>Data Embargoes</h3>
<p>All studies in SCP may enforce a data embargo that will prevent other users from downloading data files before the
embargo expires. The embargo will have a maximum length of two (2) years from date of study creation if the study is
public.</p>
<h3>Access Levels</h3>
<p>Your level of access to SCP is limited to ensure your access is no more than necessary to perform your legitimate tasks
or assigned duties. If you believe you are being granted access that you should not have, you must immediately notify
Expand Down
10 changes: 8 additions & 2 deletions app/views/studies/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@
</div>
<div class="form-group row">
<div class="col-md-3">
<%= f.label :embargo, 'Data release date' %>&nbsp;<span class='fas fa-question-circle' data-toggle='tooltip' title='Setting a data release date will prevent downloads for everyone except study owners & shared users, and will expire at 12AM on the date specified (leave blank to allow downloads)' data-placement='right'></span><br />
<%= f.date_field :embargo, class: 'form-control' %>
<%= f.label :embargo, 'Data release date' %>&nbsp;
<span class='fas fa-question-circle' data-toggle='tooltip' data-placement='right'
title='Setting a data release date will prevent downloads for everyone except study owners & shared users,
and will expire at 12AM on the date specified (leave blank to allow downloads). This has a maximum length
of <%= Study.max_embargo_text %> from date of creation for public studies.'
></span>
<br />
<%= f.date_field :embargo, class: 'form-control', max: f.object.max_embargo %>
</div>
<div class="col-md-2">
<%= f.label :public %><br />
Expand Down
10 changes: 10 additions & 0 deletions test/models/study_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,14 @@ class StudyTest < ActiveSupport::TestCase
assert_equal cells, @study.expression_matrix_cells(ann_data_file, matrix_type: 'processed')
assert_equal cells, @study.expression_matrix_cells(ann_data_file, matrix_type: 'raw')
end

test 'should prevent data embargo longer than max' do
study = FactoryBot.create(:detached_study, user: @user, name_prefix: 'Embargo Test', test_array: @@studies_to_clean)
assert study.valid?
study.embargo = study.max_embargo + 1.day
assert_not study.valid?
assert study.errors.has_key?(:embargo)
study.public = false
assert study.valid?
end
end
Loading