Commit 8daa41aa authored by Florian Hübsch's avatar Florian Hübsch
Browse files

Refactor Sample Details, add external_label to samples.

parent c76d142f
...@@ -76,6 +76,7 @@ module Chemotion ...@@ -76,6 +76,7 @@ module Chemotion
params do params do
requires :id, type: Integer, desc: "Sample id" requires :id, type: Integer, desc: "Sample id"
optional :name, type: String, desc: "Sample name" optional :name, type: String, desc: "Sample name"
optional :external_label, type: String, desc: "Sample external label"
optional :amount_value, type: Float, desc: "Sample amount_value" optional :amount_value, type: Float, desc: "Sample amount_value"
optional :amount_unit, type: String, desc: "Sample amount_unit" optional :amount_unit, type: String, desc: "Sample amount_unit"
optional :description, type: String, desc: "Sample description" optional :description, type: String, desc: "Sample description"
...@@ -106,6 +107,7 @@ module Chemotion ...@@ -106,6 +107,7 @@ module Chemotion
desc "Create a sample" desc "Create a sample"
params do params do
requires :name, type: String, desc: "Sample name" requires :name, type: String, desc: "Sample name"
optional :external_label, type: String, desc: "Sample external label"
requires :amount_value, type: Float, desc: "Sample amount_value" requires :amount_value, type: Float, desc: "Sample amount_value"
requires :amount_unit, type: String, desc: "Sample amount_unit" requires :amount_unit, type: String, desc: "Sample amount_unit"
requires :description, type: String, desc: "Sample description" requires :description, type: String, desc: "Sample description"
......
...@@ -152,6 +152,7 @@ class ElementActions { ...@@ -152,6 +152,7 @@ class ElementActions {
id: '_new_', id: '_new_',
type: 'sample', type: 'sample',
name: 'New Sample', name: 'New Sample',
external_label: '',
amount_value: 0, amount_value: 0,
amount_unit: 'g', amount_unit: 'g',
description: '', description: '',
......
import 'whatwg-fetch'; import 'whatwg-fetch';
import Sample from '../models/Sample'; import Sample from '../models/Sample';
import SampleProxy from '../proxies/SampleProxy';
// TODO: SamplesFetcher also updates Samples and so on...naming? // TODO: SamplesFetcher also updates Samples and so on...naming?
...@@ -11,7 +12,7 @@ export default class SamplesFetcher { ...@@ -11,7 +12,7 @@ export default class SamplesFetcher {
.then((response) => { .then((response) => {
return response.json() return response.json()
}).then((json) => { }).then((json) => {
return new Sample(json.sample); return new SampleProxy(json.sample);
}).catch((errorMessage) => { }).catch((errorMessage) => {
console.log(errorMessage); console.log(errorMessage);
}); });
...@@ -52,6 +53,7 @@ export default class SamplesFetcher { ...@@ -52,6 +53,7 @@ export default class SamplesFetcher {
}, },
body: JSON.stringify({ body: JSON.stringify({
name: paramObj.name, name: paramObj.name,
external_label: paramObj.external_label,
amount_value: paramObj.amount_value, amount_value: paramObj.amount_value,
amount_unit: paramObj.amount_unit, amount_unit: paramObj.amount_unit,
description: paramObj.description, description: paramObj.description,
...@@ -79,6 +81,7 @@ export default class SamplesFetcher { ...@@ -79,6 +81,7 @@ export default class SamplesFetcher {
}, },
body: JSON.stringify({ body: JSON.stringify({
name: paramObj.name, name: paramObj.name,
external_label: paramObj.external_label,
amount_value: paramObj.amount_value, amount_value: paramObj.amount_value,
amount_unit: paramObj.amount_unit, amount_unit: paramObj.amount_unit,
description: paramObj.description, description: paramObj.description,
......
...@@ -6,6 +6,11 @@ export default class Sample { ...@@ -6,6 +6,11 @@ export default class Sample {
Object.assign(this, args); Object.assign(this, args);
} }
// methods regarding sharing and sample detail levels
isRestricted() {
return this.is_restricted;
}
get name() { get name() {
return this._name return this._name
} }
...@@ -14,10 +19,42 @@ export default class Sample { ...@@ -14,10 +19,42 @@ export default class Sample {
this._name = name this._name = name
} }
get external_label() {
return this._external_label;
}
set external_label(label) {
this._external_label = label;
}
get location() {
return this._location;
}
set location(location) {
this._location = location;
}
get description() {
return this._description;
}
set description(description) {
this._description = description;
}
get impurities() {
return this._impurities;
}
set impurities(impurities) {
this._impurities = impurities;
}
get amount() { get amount() {
return({ return({
value: amount_value, value: this.amount_value,
unit: amount_unit unit: this.amount_unit
}) })
} }
...@@ -66,11 +103,17 @@ export default class Sample { ...@@ -66,11 +103,17 @@ export default class Sample {
return amount_mg; return amount_mg;
break; break;
case 'ml': case 'ml':
return amount_mg / this.molecule_density; let molecule_density = this.molecule_density;
break; if(molecule_density) {
return amount_mg / this.molecule_density;
break;
}
case 'mmol': case 'mmol':
return amount_mg * this.purity / this.molecule_molecular_weight; let molecule_molecular_weight = this.molecule_molecular_weight
break; if (molecule_molecular_weight) {
return amount_mg * this.purity / molecule_molecular_weight;
break;
}
default: default:
return amount_mg return amount_mg
} }
...@@ -96,10 +139,38 @@ export default class Sample { ...@@ -96,10 +139,38 @@ export default class Sample {
return this.molecule && this.molecule.density || 1.0 return this.molecule && this.molecule.density || 1.0
} }
set molecule_density(density) {
this.molecule.density = density;
}
get molecule_molecular_weight() { get molecule_molecular_weight() {
return this.molecule && this.molecule.molecular_weight return this.molecule && this.molecule.molecular_weight
} }
get molecule_formula() {
return this.molecule && this.molecule.sum_formular;
}
get molecule_inchistring() {
return this.molecule && this.molecule.inchistring;
}
get molecule_boiling_point() {
return this.molecule && this.molecule.boiling_point;
}
set molecule_boiling_point(bp) {
this.molecule.boiling_point = bp;
}
get molecule_melting_point() {
return this.molecule && this.molecule.melting_point;
}
set molecule_melting_point(mp) {
this.molecule.melting_point = mp;
}
get purity() { get purity() {
return this._purity || 1.0 return this._purity || 1.0
} }
...@@ -115,5 +186,4 @@ export default class Sample { ...@@ -115,5 +186,4 @@ export default class Sample {
set molecule(molecule) { set molecule(molecule) {
this._molecule = new Molecule(molecule) this._molecule = new Molecule(molecule)
} }
}; };
import Sample from '../models/Sample';
import Molecule from '../models/Molecule';
export default class SampleProxy extends Sample {
constructor(args) {
super(args)
let sampleMethodsWithGetAndSet = [
'name', 'external_label', 'location', 'description', 'impurities', 'amount_unit', 'amount_value', 'purity'
]
sampleMethodsWithGetAndSet.forEach((m) => {
Object.defineProperty(this, m, {
get: function() { return this.methodOrRestrictionPattern(m) },
set: function(arg) { super[m] = arg }
})
})
let sampleMethodsWithGet = [
'amount_mg', 'amount_ml', 'amount_mmol'
]
sampleMethodsWithGet.forEach((m) => {
Object.defineProperty(this, m, {
get: function() { return this.methodOrRestrictionPattern(m) },
})
})
let moleculeMethodsWithGetAndSet = [
'molecule_density', 'molecule_boiling_point', 'molecule_melting_point'
]
moleculeMethodsWithGetAndSet.forEach((m) => {
Object.defineProperty(this, m, {
get: function() { return this.methodOnMoleculeOrRestrictionPattern(m) },
set: function(arg) { super[m] = arg }
})
})
let moleculeMethodsWithGet = [
'molecule_molecular_weight', 'molecule_formula', 'molecule_inchistring'
]
moleculeMethodsWithGet.forEach((m) => {
Object.defineProperty(this, m, {
get: function() { return this.methodOnMoleculeOrRestrictionPattern(m) },
})
})
}
get restrictionPattern() {
return '***';
}
methodOrRestrictionPattern(method) {
if(super.isRestricted && super[method] == undefined) {
return this.restrictionPattern;
} else {
return super[method];
}
}
methodOnMoleculeOrRestrictionPattern(method) {
if(super.isRestricted && super.molecule == undefined) {
return this.restrictionPattern;
} else {
return super[method];
}
}
get amount() {
return({
value: this.amount_value,
unit: this.amount_unit
})
}
get molecule() {
return this.methodOrRestrictionPattern('molecule');
}
set molecule(molecule) {
super.molecule = new Molecule(molecule)
}
}
...@@ -18,4 +18,8 @@ class User < ActiveRecord::Base ...@@ -18,4 +18,8 @@ class User < ActiveRecord::Base
def owns_unshared_collections?(collections) def owns_unshared_collections?(collections)
owns_collections?(collections) && collections.pluck(:is_shared).none? owns_collections?(collections) && collections.pluck(:is_shared).none?
end end
def name
"#{first_name} #{last_name}"
end
end end
...@@ -18,7 +18,7 @@ class SampleProxy ...@@ -18,7 +18,7 @@ class SampleProxy
sample_attr.each do |attr| sample_attr.each do |attr|
new_sample_hash[attr] = s[attr] new_sample_hash[attr] = s[attr]
end end
new_sample_hash[:is_scoped] = true new_sample_hash[:is_restricted] = true
{sample: new_sample_hash} {sample: new_sample_hash}
else else
...@@ -54,13 +54,18 @@ class SampleProxy ...@@ -54,13 +54,18 @@ class SampleProxy
[ [
:id, :id,
:type, :type,
#:weight :external_label,
:amount_value,
:amount_unit
] ]
when 1 when 1
[ [
:id, :id,
:type, :type,
:molecule :external_label,
:molecule,
:amount_value,
:amount_unit
] ]
when 2 when 2
......
class SampleSerializer < ActiveModel::Serializer class SampleSerializer < ActiveModel::Serializer
attributes :id, :type, :name, :description, :created_at, :collection_labels, :amount_value, :amount_unit, :molfile, attributes :id, :type, :name, :description, :created_at, :collection_labels, :amount_value, :amount_unit, :molfile,
:purity, :solvent, :impurities, :location, :weight, :volume, :is_top_secret, :is_scoped :purity, :solvent, :impurities, :location, :weight, :volume, :is_top_secret, :is_restricted, :external_label
has_one :molecule has_one :molecule
...@@ -29,7 +29,7 @@ class SampleSerializer < ActiveModel::Serializer ...@@ -29,7 +29,7 @@ class SampleSerializer < ActiveModel::Serializer
object.volume object.volume
end end
def is_scoped def is_restricted
false false
end end
end end
...@@ -2,7 +2,7 @@ class UserSerializer < ActiveModel::Serializer ...@@ -2,7 +2,7 @@ class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :initials attributes :id, :name, :initials
def name def name
"#{object.first_name} #{object.last_name}" object.name
end end
def initials def initials
......
...@@ -29,7 +29,7 @@ Rails.application.configure do ...@@ -29,7 +29,7 @@ Rails.application.configure do
# config.assets.css_compressor = :sass # config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed. # Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false config.assets.compile = true
# Asset digests allow you to set far-future HTTP expiration dates on all assets, # Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params. # yet still be able to expire them through the digest params.
......
class AddExternalLabelToSamples < ActiveRecord::Migration
def change
add_column :samples, :external_label, :string, default: ""
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151004084416) do ActiveRecord::Schema.define(version: 20151005151021) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -145,17 +145,18 @@ ActiveRecord::Schema.define(version: 20151004084416) do ...@@ -145,17 +145,18 @@ ActiveRecord::Schema.define(version: 20151004084416) do
t.string "name" t.string "name"
t.float "amount_value" t.float "amount_value"
t.string "amount_unit" t.string "amount_unit"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.text "description", default: "" t.text "description", default: ""
t.integer "molecule_id" t.integer "molecule_id"
t.binary "molfile" t.binary "molfile"
t.float "purity" t.float "purity"
t.string "solvent", default: "" t.string "solvent", default: ""
t.string "impurities", default: "" t.string "impurities", default: ""
t.string "location", default: "" t.string "location", default: ""
t.boolean "is_top_secret", default: false t.boolean "is_top_secret", default: false
t.string "ancestry" t.string "ancestry"
t.string "external_label", default: ""
end end
add_index "samples", ["molecule_id"], name: "index_samples_on_sample_id", using: :btree add_index "samples", ["molecule_id"], name: "index_samples_on_sample_id", using: :btree
......
...@@ -9,7 +9,7 @@ describe Chemotion::CollectionAPI do ...@@ -9,7 +9,7 @@ describe Chemotion::CollectionAPI do
} }
context 'authorized user logged in' do context 'authorized user logged in' do
let(:user) { create(:user, name: 'Musashi') } let(:user) { create(:user, first_name: 'Musashi', last_name: 'M') }
let(:u2) { create(:user) } let(:u2) { create(:user) }
let!(:c1) { create(:collection, user: user, is_shared: false) } let!(:c1) { create(:collection, user: user, is_shared: false) }
let!(:c2) { create(:collection, user: user, shared_by_id: user.id, is_shared: true) } let!(:c2) { create(:collection, user: user, shared_by_id: user.id, is_shared: true) }
...@@ -304,7 +304,7 @@ describe Chemotion::CollectionAPI do ...@@ -304,7 +304,7 @@ describe Chemotion::CollectionAPI do
post '/api/v1/collections/shared', params post '/api/v1/collections/shared', params
# naming convention for shared collections # naming convention for shared collections
c = Collection.find_by(label: 'My project with Musashi') c = Collection.find_by(label: 'My project with Musashi M')
expect(c).to_not be_nil expect(c).to_not be_nil
expect(c.user_id).to eq user.id expect(c.user_id).to eq user.id
expect(c.samples).to match_array [s1, s2] expect(c.samples).to match_array [s1, s2]
...@@ -347,7 +347,7 @@ describe Chemotion::CollectionAPI do ...@@ -347,7 +347,7 @@ describe Chemotion::CollectionAPI do
it 'creates no shared collection' do it 'creates no shared collection' do
post '/api/v1/collections/shared', params post '/api/v1/collections/shared', params
c = Collection.find_by(label: 'My project with Musashi') c = Collection.find_by(label: 'My project with Musashi M')
expect(c).to be_nil expect(c).to be_nil
end end
end end
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment