canvas-lms/app/models/custom_data.rb

129 lines
3.0 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
#
# Copyright (C) 2014 - present Instructure, Inc.
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class CustomData < ActiveRecord::Base
class WriteConflict < Exception
attr_accessor :conflict_scope, :type_at_conflict, :value_at_conflict
def initialize(opts = {})
opts.each do |k,v|
instance_variable_set("@#{k}", v)
end
super 'write conflict for custom_data hash'
end
def as_json
{
conflict_scope: conflict_scope,
type_at_conflict: type_at_conflict,
value_at_conflict: value_at_conflict
}
end
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
end
self.table_name = 'custom_data'
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
belongs_to :user
serialize :data, Hash
validates_presence_of :user, :namespace
def get_data(scope)
hash_data_from_scope(data_frd, "d/#{scope}")
end
def lock_and_save
transaction do
self.lock!
yield
self.destroyed? || save
end
end
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
def set_data(scope, val)
set_hash_data_from_scope(data_frd, "d/#{scope}", val)
end
def delete_data(scope)
delete_hash_data_from_scope(data_frd, "d/#{scope}")
end
private
def hash_data_from_scope(hash, scope)
keys = scope.split('/')
keys.inject(hash) do |hash, k|
raise ArgumentError, 'invalid scope for hash' unless hash.is_a? Hash
hash[k]
end
end
def set_hash_data_from_scope(hash, scope, data)
keys = scope.split('/')
last = keys.pop
traverse = ->(hsh, key_idx) do
return hsh if key_idx == keys.length
k = keys[key_idx]
h = hsh[k]
if h.nil?
hsh[k] = {}
elsif !h.is_a? Hash
raise WriteConflict.new({
conflict_scope: keys.slice(1..key_idx).join('/'),
type_at_conflict: h.class,
value_at_conflict: h
})
end
traverse.call(hsh[k], key_idx+1)
end
h = traverse.call(hash, 0)
overwrite = !h[last].nil?
h[last] = data
overwrite
end
def delete_hash_data_from_scope(hash, scope)
keys = scope.split('/')
del_frd = ->(hash) do
k = keys.shift
if keys.empty?
raise ArgumentError, 'invalid scope for hash' unless hash.has_key? k
hash.delete k
else
h = hash[k]
raise ArgumentError, 'invalid scope for hash' if h.nil?
ret = del_frd.call(h)
hash.delete k if h.empty?
ret
end
end
ret = del_frd.call(hash)
self.destroy if hash.empty?
ret
end
def data_frd
read_or_initialize_attribute(:data, {})
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
end
end