From 212b3f798edb6cc766517a31a5a551c5fe4f8807 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Mon, 9 May 2016 13:17:18 -0400 Subject: [PATCH 01/13] Consistent indentation --- .editorconfig | 6 +++--- addon/adapters/node.js | 4 ++-- addon/serializers/application.js | 18 ++++++++-------- tests/dummy/app/router.js | 2 +- tests/dummy/app/routes/nodes.js | 2 +- tests/dummy/app/routes/nodes/detail.js | 2 +- tests/dummy/app/templates/nodes/index.hbs | 26 +++++++++++------------ 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9a13d9b1e..3ef6636ee 100644 --- a/.editorconfig +++ b/.editorconfig @@ -20,15 +20,15 @@ indent_size = 4 [*.hbs] insert_final_newline = false indent_style = space -indent_size = 2 +indent_size = 4 [*.css] indent_style = space -indent_size = 2 +indent_size = 4 [*.html] indent_style = space -indent_size = 2 +indent_size = 4 [*.{diff,md}] trim_trailing_whitespace = false diff --git a/addon/adapters/node.js b/addon/adapters/node.js index 6e925e874..5ce0d304d 100644 --- a/addon/adapters/node.js +++ b/addon/adapters/node.js @@ -2,7 +2,7 @@ import ApplicationAdapter from './application'; export default ApplicationAdapter.extend({ buildURL() { - // Embed contributors - return `${this._super(...arguments)}?embed=contributors`; + // Embed contributors + return `${this._super(...arguments)}?embed=contributors`; } }); diff --git a/addon/serializers/application.js b/addon/serializers/application.js index d8cdbd6ad..5b752e78d 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -10,11 +10,11 @@ export default DS.JSONAPISerializer.extend({ return normalized; }, _normalizeRecord(record) { - record.attributes = this._normalizeAttributes(record.attributes); - if (record.links) { - record.attributes.links = record.links; - } - return record; + record.attributes = this._normalizeAttributes(record.attributes); + if (record.links) { + record.attributes.links = record.links; + } + return record; }, normalizeSingleResponse(_, __, payload) { payload.data = this._normalizeRecord(payload.data); @@ -25,12 +25,12 @@ export default DS.JSONAPISerializer.extend({ return this._super(...arguments); }, keyForAttribute(key) { - return Ember.String.camelize(key); + return Ember.String.camelize(key); }, serializeIntoHash(/*hash, typeClass, snapshot, options*/) { - // Don't send links as part of hash - // TODO - return this._super(...arguments); + // Don't send links as part of hash + // TODO + return this._super(...arguments); } }); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 5a1c57bf8..db980d984 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -8,7 +8,7 @@ const Router = Ember.Router.extend({ Router.map(function() { this.route('index', {path: '/'}); this.route('nodes', function() { - this.route('detail', {path: '/:node_id'}); + this.route('detail', {path: '/:node_id'}); }); this.route('login'); }); diff --git a/tests/dummy/app/routes/nodes.js b/tests/dummy/app/routes/nodes.js index 427ddbb94..4d5032adf 100644 --- a/tests/dummy/app/routes/nodes.js +++ b/tests/dummy/app/routes/nodes.js @@ -6,6 +6,6 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { session: Ember.inject.service(), model() { const user = this.modelFor('application'); - return user.get('nodes'); + return user.get('nodes'); // Fetch from `/users/me/nodes/` } }); diff --git a/tests/dummy/app/routes/nodes/detail.js b/tests/dummy/app/routes/nodes/detail.js index b711cbe5f..ccd983323 100644 --- a/tests/dummy/app/routes/nodes/detail.js +++ b/tests/dummy/app/routes/nodes/detail.js @@ -2,6 +2,6 @@ import Ember from 'ember'; export default Ember.Route.extend({ model(params) { - return this.store.findRecord('node', params.node_id); + return this.store.findRecord('node', params.node_id); } }); diff --git a/tests/dummy/app/templates/nodes/index.hbs b/tests/dummy/app/templates/nodes/index.hbs index 6058e0729..6234c45dd 100644 --- a/tests/dummy/app/templates/nodes/index.hbs +++ b/tests/dummy/app/templates/nodes/index.hbs @@ -1,16 +1,16 @@

My Nodes

{{#each model as |node|}} -
-
-

{{node.title}}

-

{{node.category}}

-

{{moment-format node.dateCreated}}

-

{{moment-format node.dateModified}}

-

- - View on OSF - - {{link-to 'Detail' 'nodes.detail' node.id class="btn btn-primary"}} -

-
+
+
+

{{node.title}}

+

{{node.category}}

+

{{moment-format node.dateCreated}}

+

{{moment-format node.dateModified}}

+

+ + View on OSF + + {{link-to 'Detail' 'nodes.detail' node.id class="btn btn-primary"}} +

+
{{/each}} From 6f3d0e0fde688da74045dc590e9483c2a329270c Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Mon, 9 May 2016 13:17:42 -0400 Subject: [PATCH 02/13] Make .env ignores general --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0cab8edcb..c0799bbff 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,5 @@ npm-debug.log testem.log .env -.env-local -.env-stage* -.env-prod +.env-* From 9408bb273e91e77186291db6d94ea2442c0c6fb9 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Mon, 9 May 2016 16:01:31 -0400 Subject: [PATCH 03/13] Simplify serializer logic --- addon/serializers/application.js | 38 +++++++---------------- tests/dummy/app/templates/nodes/index.hbs | 8 ++--- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/addon/serializers/application.js b/addon/serializers/application.js index 5b752e78d..5f185b232 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -2,35 +2,19 @@ import Ember from 'ember'; import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ - _normalizeAttributes(attributes) { - var normalized = {}; - Object.keys(attributes).forEach(function(key) { - normalized[Ember.String.camelize(key)] = attributes[key]; - }); - return normalized; - }, - _normalizeRecord(record) { - record.attributes = this._normalizeAttributes(record.attributes); - if (record.links) { - record.attributes.links = record.links; + extractAttributes(modelClass, resourceHash) { + //ApiV2 `links` exist outside the attributes field; make them accessible to the data model + if (resourceHash.links) { // TODO: Should also test whether model class defines a links field + resourceHash.attributes.links = resourceHash.links; } - return record; - }, - normalizeSingleResponse(_, __, payload) { - payload.data = this._normalizeRecord(payload.data); - return this._super(...arguments); - }, - normalizeArrayResponse(_, __, payload) { - payload.data = payload.data.map(this._normalizeRecord.bind(this)); - return this._super(...arguments); - }, - keyForAttribute(key) { - return Ember.String.camelize(key); + return this._super(modelClass, resourceHash); }, - serializeIntoHash(/*hash, typeClass, snapshot, options*/) { - // Don't send links as part of hash - // TODO - return this._super(...arguments); + keyForAttribute(key, method) { + if (method === 'deserialize') { + return Ember.String.underscore(key); + } else if (method === 'serialize') { // TOOD: Is this needed? Test serialization + return Ember.String.camelize(key); + } } }); diff --git a/tests/dummy/app/templates/nodes/index.hbs b/tests/dummy/app/templates/nodes/index.hbs index 6234c45dd..4f00c6306 100644 --- a/tests/dummy/app/templates/nodes/index.hbs +++ b/tests/dummy/app/templates/nodes/index.hbs @@ -2,10 +2,10 @@ {{#each model as |node|}}
-

{{node.title}}

-

{{node.category}}

-

{{moment-format node.dateCreated}}

-

{{moment-format node.dateModified}}

+

{{node.title}}

+

{{node.category}}

+

{{moment-format node.dateCreated}}

+

{{moment-format node.dateModified}}

View on OSF From ac26c9944039dbea2301c252e3b2243443bc1566 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Mon, 9 May 2016 16:54:57 -0400 Subject: [PATCH 04/13] Semantic heading levels, not stylistic --- tests/dummy/app/templates/application.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs index 979afbede..5d6d4df6d 100644 --- a/tests/dummy/app/templates/application.hbs +++ b/tests/dummy/app/templates/application.hbs @@ -1,6 +1,6 @@

{{link-to 'Home' 'index' class="btn btn-default"}} -

Welcome to OSF Ember Example App

+

Welcome to OSF Ember Example App

{{outlet}} From e6bc06d08cf50cad8691d59a50b5ef416d9fa814 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 10:19:29 -0400 Subject: [PATCH 05/13] Simplify URL logic and always append trailing slash (to0 avoid redirects on preflighting; DRF seems to insist on trialing slash) --- addon/adapters/application.js | 13 ++++++++----- index.js | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/addon/adapters/application.js b/addon/adapters/application.js index 9f4b34755..4e26d40ae 100644 --- a/addon/adapters/application.js +++ b/addon/adapters/application.js @@ -8,11 +8,14 @@ export default DS.JSONAPIAdapter.extend(DataAdapterMixin, { authorizer: 'authorizer:osf-token', host: config.OSF.apiUrl, + namespace: config.OSF.apiNamespace, pathForType: Ember.String.pluralize, - urlForFindRecord (id, modelName/*, snapshot*/) { - return `${this.get('host')}${Ember.String.pluralize(modelName)}/${id}/`; - }, - urlForFindAll (modelName) { - return `${this.get('host')}${Ember.String.pluralize(modelName)}/`; + + buildURL() { + var url = this._super(...arguments); + if (!url.endsWith('/')) { + url += '/'; + } + return url; } }); diff --git a/index.js b/index.js index efab97a95..d88f8bf6d 100644 --- a/index.js +++ b/index.js @@ -17,30 +17,30 @@ module.exports = { ENV.OSF = { clientId: process.env.OSF_CLIENT_ID, - scope: process.env.OSF_SCOPE + scope: process.env.OSF_SCOPE, + apiNamespace: 'v2' // URL suffix (after host) }; - if (environment === 'development') { - ENV.OSF.url = 'http://localhost:5000/'; - ENV.OSF.apiUrl = 'http://localhost:8000/v2/'; + ENV.OSF.url = 'http://localhost:5000'; + ENV.OSF.apiUrl = 'http://localhost:8000'; ENV.OSF.authUrl = 'http://localhost:8080/oauth2/profile'; ENV.OSF.accessToken = process.env.OSF_ACCESS_TOKEN; ENV.DEV = true; } if (environment === 'staging') { - ENV.OSF.url = 'https://staging.osf.io/'; - ENV.OSF.apiUrl = 'https://staging-api.osf.io/v2/'; + ENV.OSF.url = 'https://staging.osf.io'; + ENV.OSF.apiUrl = 'https://staging-api.osf.io'; ENV.OSF.authUrl = 'https://staging-accounts.osf.io/oauth2/authorize'; } if (environment === 'staging2') { - ENV.OSF.url = 'https://staging2.osf.io/'; - ENV.OSF.apiUrl = 'https://staging2-api.osf.io/v2/'; + ENV.OSF.url = 'https://staging2.osf.io'; + ENV.OSF.apiUrl = 'https://staging2-api.osf.io'; ENV.OSF.authUrl = 'https://staging2-accounts.osf.io/oauth2/authorize'; } if (environment === 'production') { - ENV.OSF.url = 'https://osf.io/'; - ENV.OSF.apiUrl = 'https://api.osf.io/v2/'; + ENV.OSF.url = 'https://osf.io'; + ENV.OSF.apiUrl = 'https://api.osf.io'; ENV.OSF.authUrl = 'https://accounts.osf.io/oauth2/authorize'; } From f0f02afe870bbcdfafd0aacb1d409956dcc9a388 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 10:52:13 -0400 Subject: [PATCH 06/13] Misc cleanup --- addon/adapters/node.js | 1 + addon/authenticators/osf-token.js | 2 +- addon/models/node.js | 2 +- tests/dummy/app/router.js | 2 +- tests/dummy/app/routes/nodes.js | 9 +++++++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/addon/adapters/node.js b/addon/adapters/node.js index 5ce0d304d..bb3b9a8fa 100644 --- a/addon/adapters/node.js +++ b/addon/adapters/node.js @@ -3,6 +3,7 @@ import ApplicationAdapter from './application'; export default ApplicationAdapter.extend({ buildURL() { // Embed contributors + // TODO: We only want to add the embed parameter on GET requests (not POST) return `${this._super(...arguments)}?embed=contributors`; } }); diff --git a/addon/authenticators/osf-token.js b/addon/authenticators/osf-token.js index 470c8730d..9727ff8a4 100644 --- a/addon/authenticators/osf-token.js +++ b/addon/authenticators/osf-token.js @@ -9,7 +9,7 @@ export default BaseAuthenticator.extend({ _test (accessToken) { return Ember.$.ajax({ method: 'GET', - url: `${config.OSF.apiUrl}users/me/`, + url: `${config.OSF.apiUrl}/${config.OSF.apiNamespace}/users/me/`, dataType: 'json', contentType: 'application/json', xhrFields: {withCredentials: false}, diff --git a/addon/models/node.js b/addon/models/node.js index 069c2313b..25e5fbd3b 100644 --- a/addon/models/node.js +++ b/addon/models/node.js @@ -34,7 +34,7 @@ export default OsfModel.extend({ //forkedFrom: DS.belongsTo('node'), //nodeLinks: DS.hasMany('node-pointers'), //registrations: DS.hasMany('registrations'), - //primaryInistution: DS.belongsTo('institution'), + //primaryInstitution: DS.belongsTo('institution'), root: DS.belongsTo('node') //logs: DS.hasMany('node-logs'), }); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index db980d984..dc7d751eb 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -8,7 +8,7 @@ const Router = Ember.Router.extend({ Router.map(function() { this.route('index', {path: '/'}); this.route('nodes', function() { - this.route('detail', {path: '/:node_id'}); + this.route('detail', {path: '/:node_id'}); }); this.route('login'); }); diff --git a/tests/dummy/app/routes/nodes.js b/tests/dummy/app/routes/nodes.js index 4d5032adf..4ef33ccd9 100644 --- a/tests/dummy/app/routes/nodes.js +++ b/tests/dummy/app/routes/nodes.js @@ -7,5 +7,14 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { model() { const user = this.modelFor('application'); return user.get('nodes'); // Fetch from `/users/me/nodes/` + }, + + actions: { + createNew() { + // TODO: Just hardcode a payload here, tests POST + console.log('button was clicked'); + //var record = this.store.createRecord('node', {}); // TODO write + //record.save(); + } } }); From ca7bef22cba74762c0b1691ec564201f059e8020 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 11:56:29 -0400 Subject: [PATCH 07/13] Add wip code to create/edit (test server writes) --- addon/serializers/application.js | 10 +++++- tests/dummy/app/routes/nodes/detail.js | 20 +++++++++++ tests/dummy/app/templates/nodes/detail.hbs | 40 ++++++++++++++-------- tests/dummy/app/templates/nodes/index.hbs | 4 +++ 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/addon/serializers/application.js b/addon/serializers/application.js index 5f185b232..97829761e 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -3,7 +3,7 @@ import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ extractAttributes(modelClass, resourceHash) { - //ApiV2 `links` exist outside the attributes field; make them accessible to the data model + // ApiV2 `links` exist outside the attributes field; make them accessible to the data model if (resourceHash.links) { // TODO: Should also test whether model class defines a links field resourceHash.attributes.links = resourceHash.links; } @@ -17,4 +17,12 @@ export default DS.JSONAPISerializer.extend({ return Ember.String.camelize(key); } } + + + // TODO: Sending back to server requires + // 1. Remove links from payload (try something like serializer attrs: field{serialize:false}), and what happens if record has no links field? + // 2. Rename keys in payload (try setting something with snake case) + // 3. Veirfy post, put, and patch operations + // 4. Don't send relationships, if that breaks writing operations + }); diff --git a/tests/dummy/app/routes/nodes/detail.js b/tests/dummy/app/routes/nodes/detail.js index ccd983323..a90314bff 100644 --- a/tests/dummy/app/routes/nodes/detail.js +++ b/tests/dummy/app/routes/nodes/detail.js @@ -3,5 +3,25 @@ import Ember from 'ember'; export default Ember.Route.extend({ model(params) { return this.store.findRecord('node', params.node_id); + }, + + setupController(controller, model) { + controller.set('editedTitle', model.get('title')); + this._super(...arguments); + }, + + actions: { + editExisting(value) { + // TODO: Should test PUT or PATCH + console.log('Will edit title from', this.modelFor(this.routeName).get('title'), ' to ', value); + var node = this.modelFor(this.routeName); + if (node.get('currentUserPermissions').indexOf('write') !== -1) { + node.set('title', value); + node.save(); + } else { + console.log('You do not have permissions to edit this node'); + } + } } + }); diff --git a/tests/dummy/app/templates/nodes/detail.hbs b/tests/dummy/app/templates/nodes/detail.hbs index 914145e0f..05bba69c0 100644 --- a/tests/dummy/app/templates/nodes/detail.hbs +++ b/tests/dummy/app/templates/nodes/detail.hbs @@ -1,26 +1,38 @@ {{link-to 'Back to list' 'nodes' class="btn btn-default"}}
-

{{model.title}}

-

{{model.category}}

-

{{moment-format model.dateCreated}}

-

{{moment-format model.dateModified}}

+ +

Data

+

{{model.title}}

+

{{model.category}}

+

{{moment-format model.dateCreated}}

+

{{moment-format model.dateModified}}

View on OSF


-

- -

+ +

Contributors

+ - {{#each model.contributors as |contrib|}} - - {{contrib.bibliographic}} - - {{/each}} + + + + + {{#each model.contributors as |contrib|}} + + + + + {{/each}}
IDAuthor?
{{contrib.id}}{{contrib.bibliographic}}
-

-

+ + + +

Edit this node

+ Title: {{input value=editedTitle}} + +
diff --git a/tests/dummy/app/templates/nodes/index.hbs b/tests/dummy/app/templates/nodes/index.hbs index 4f00c6306..3926175a0 100644 --- a/tests/dummy/app/templates/nodes/index.hbs +++ b/tests/dummy/app/templates/nodes/index.hbs @@ -1,4 +1,8 @@

My Nodes

+ + + + {{#each model as |node|}}
From 07e54677ef8f1f3353c223c43d13b40fad941ff9 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 13:33:30 -0400 Subject: [PATCH 08/13] Fix merge goofs --- addon/serializers/application.js | 4 ++-- index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/serializers/application.js b/addon/serializers/application.js index 0ed9640de..7a0927e58 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -9,7 +9,7 @@ export default DS.JSONAPISerializer.extend({ } if (resourceHash.embeds) { // TODO, actually merge in embedded data? - resourceHash.attributes.embeds = record.embeds; + resourceHash.attributes.embeds = resourceHash.embeds; } return this._super(modelClass, resourceHash); }, @@ -21,7 +21,7 @@ export default DS.JSONAPISerializer.extend({ return Ember.String.camelize(key); } } - + // TODO: Sending back to server requires // 1. Remove links from payload (try something like serializer attrs: field{serialize:false}), and what happens if record has no links field? // 2. Rename keys in payload (try setting something with snake case) diff --git a/index.js b/index.js index 83c840c9f..5307478f1 100644 --- a/index.js +++ b/index.js @@ -22,7 +22,7 @@ module.exports = { if (BACKEND === 'local') { ENV.OSF.url = 'http://localhost:5000/'; - ENV.OSF.apiUrl = 'http://localhost:8000/v2/'; + ENV.OSF.apiUrl = 'http://localhost:8000'; ENV.OSF.authUrl = 'http://localhost:8080/oauth2/profile'; ENV.OSF.accessToken = SETTINGS.PERSONAL_ACCESS_TOKEN; @@ -46,6 +46,6 @@ module.exports = { ENV['ember-simple-auth'] = { authorizer: 'authorizer:osf-token' - }; + }; } }; From 6c6fb336b907a7c30f721a24e8856d780b99f2b8 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 14:06:36 -0400 Subject: [PATCH 09/13] More style cleanup --- addon/adapters/application.js | 1 + index.js | 74 ++++++++++++++++----------------- tests/dummy/app/routes/nodes.js | 2 +- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/addon/adapters/application.js b/addon/adapters/application.js index 657314ce7..3a80a17ea 100644 --- a/addon/adapters/application.js +++ b/addon/adapters/application.js @@ -12,6 +12,7 @@ export default DS.JSONAPIAdapter.extend(DataAdapterMixin, { buildURL() { var url = this._super(...arguments); + // TODO: Is this still necessary? if (!url.endsWith('/')) { url += '/'; } diff --git a/index.js b/index.js index 5307478f1..4af250e3c 100644 --- a/index.js +++ b/index.js @@ -5,47 +5,47 @@ var config = require('config'); module.exports = { name: 'ember-osf', config: function(environment, ENV) { - let BACKEND = process.env.BACKEND || 'local'; - let SETTINGS = {}; - try { - SETTINGS = config.get(BACKEND); - } - catch (e) { - console.log(`WARNING: you have specified a backend '${BACKEND}' that you have not configured in your config/.yml`); - } + let BACKEND = process.env.BACKEND || 'local'; + let SETTINGS = {}; + try { + SETTINGS = config.get(BACKEND); + } + catch (e) { + console.log(`WARNING: you have specified a backend '${BACKEND}' that you have not configured in your config/.yml`); + } - ENV.OSF = { - clientId: SETTINGS.CLIENT_ID, - scope: SETTINGS.OAUTH_SCOPES, - apiNamespace: 'v2' // URL suffix (after host) + ENV.OSF = { + clientId: SETTINGS.CLIENT_ID, + scope: SETTINGS.OAUTH_SCOPES, + apiNamespace: 'v2' // URL suffix (after host) }; - if (BACKEND === 'local') { - ENV.OSF.url = 'http://localhost:5000/'; - ENV.OSF.apiUrl = 'http://localhost:8000'; - ENV.OSF.authUrl = 'http://localhost:8080/oauth2/profile'; + if (BACKEND === 'local') { + ENV.OSF.url = 'http://localhost:5000/'; + ENV.OSF.apiUrl = 'http://localhost:8000'; + ENV.OSF.authUrl = 'http://localhost:8080/oauth2/profile'; - ENV.OSF.accessToken = SETTINGS.PERSONAL_ACCESS_TOKEN; - ENV.OSF.local = true; - } - if (BACKEND === 'stage') { - ENV.OSF.url = 'https://staging.osf.io/'; - ENV.OSF.apiUrl = 'https://staging-api.osf.io'; - ENV.OSF.authUrl = 'https://staging-accounts.osf.io/oauth2/authorize'; - } - if (BACKEND === 'stage2') { - ENV.OSF.url = 'https://staging2.osf.io/'; - ENV.OSF.apiUrl = 'https://staging2-api.osf.io'; - ENV.OSF.authUrl = 'https://staging2-accounts.osf.io/oauth2/authorize'; - } - if (BACKEND === 'prod') { - ENV.OSF.url = 'https://osf.io/'; - ENV.OSF.apiUrl = 'https://api.osf.io'; - ENV.OSF.authUrl = 'https://accounts.osf.io/oauth2/authorize'; - } + ENV.OSF.accessToken = SETTINGS.PERSONAL_ACCESS_TOKEN; + ENV.OSF.local = true; + } + if (BACKEND === 'stage') { + ENV.OSF.url = 'https://staging.osf.io/'; + ENV.OSF.apiUrl = 'https://staging-api.osf.io'; + ENV.OSF.authUrl = 'https://staging-accounts.osf.io/oauth2/authorize'; + } + if (BACKEND === 'stage2') { + ENV.OSF.url = 'https://staging2.osf.io/'; + ENV.OSF.apiUrl = 'https://staging2-api.osf.io'; + ENV.OSF.authUrl = 'https://staging2-accounts.osf.io/oauth2/authorize'; + } + if (BACKEND === 'prod') { + ENV.OSF.url = 'https://osf.io/'; + ENV.OSF.apiUrl = 'https://api.osf.io'; + ENV.OSF.authUrl = 'https://accounts.osf.io/oauth2/authorize'; + } - ENV['ember-simple-auth'] = { - authorizer: 'authorizer:osf-token' - }; + ENV['ember-simple-auth'] = { + authorizer: 'authorizer:osf-token' + }; } }; diff --git a/tests/dummy/app/routes/nodes.js b/tests/dummy/app/routes/nodes.js index 058cb1a75..0a3f1c5ef 100644 --- a/tests/dummy/app/routes/nodes.js +++ b/tests/dummy/app/routes/nodes.js @@ -10,7 +10,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { return user.get('nodes'); // Fetch from `/users/me/nodes/` } else { - return this.get('store').findRecord('user', 'me').then (user => user.get('nodes')); + return this.get('store').findRecord('user', 'me').then(user => user.get('nodes')); } }, actions: { From c4882dc4cd848f1dd9fc5f96286def02bee1635c Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 17:22:42 -0400 Subject: [PATCH 10/13] Exclude links, embeds, and relationships from payload --- addon/mixins/osf-login-route.js | 3 ++- addon/serializers/application.js | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/addon/mixins/osf-login-route.js b/addon/mixins/osf-login-route.js index 6fed1cd3f..f8ed29827 100644 --- a/addon/mixins/osf-login-route.js +++ b/addon/mixins/osf-login-route.js @@ -10,8 +10,9 @@ export default Ember.Mixin.create(UnauthenticatedRouteMixin, { if (config.OSF.isLocal) { accessToken = config.OSF.accessToken; } else { - // Acquire an OSF access token, then exchange it for a Jam token + // Acquire an OSF access token, then exchange it for a Jam token // TODO: Jam? var hash = window.location.hash.substring(1).split('&').map(function(str) { + // TODO: Comma expression; check with Sam on intent return this[str.split('=')[0]] = str.split('=')[1], this; }.bind({}))[0]; if (!hash || !hash.access_token) { diff --git a/addon/serializers/application.js b/addon/serializers/application.js index 7a0927e58..9358bd6c9 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -2,13 +2,17 @@ import Ember from 'ember'; import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ + attrs: { + links: {serialize: false}, + embeds: {serialize: false} + }, + extractAttributes(modelClass, resourceHash) { // ApiV2 `links` exist outside the attributes field; make them accessible to the data model if (resourceHash.links) { // TODO: Should also test whether model class defines a links field resourceHash.attributes.links = resourceHash.links; } if (resourceHash.embeds) { - // TODO, actually merge in embedded data? resourceHash.attributes.embeds = resourceHash.embeds; } return this._super(modelClass, resourceHash); @@ -17,15 +21,15 @@ export default DS.JSONAPISerializer.extend({ keyForAttribute(key, method) { if (method === 'deserialize') { return Ember.String.underscore(key); - } else if (method === 'serialize') { // TOOD: Is this needed? Test serialization + } else if (method === 'serialize') { return Ember.String.camelize(key); } - } - - // TODO: Sending back to server requires - // 1. Remove links from payload (try something like serializer attrs: field{serialize:false}), and what happens if record has no links field? - // 2. Rename keys in payload (try setting something with snake case) - // 3. Veirfy post, put, and patch operations - // 4. Don't send relationships, if that breaks writing operations + }, + serialize: function(snapshot, options) { + var serialized = this._super(snapshot, options); + // Don't send relationships to the server; this can lead to 500 errors. + delete serialized.data.relationships; + return serialized; + } }); From 6b3d6f49fe95c0e817dea87b1bdf174eb92e5f4c Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 17:30:07 -0400 Subject: [PATCH 11/13] Remove two unused dependencies --- addon/serializers/application.js | 2 ++ package.json | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/serializers/application.js b/addon/serializers/application.js index 9358bd6c9..bed8dbf8c 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -2,6 +2,8 @@ import Ember from 'ember'; import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ + + // TODO: Pre-1.0, refactor this into a separate OSF serializer, so we can support other microservices such as WB attrs: { links: {serialize: false}, embeds: {serialize: false} diff --git a/package.json b/package.json index 158f93502..07ab56a32 100644 --- a/package.json +++ b/package.json @@ -55,12 +55,10 @@ "ember-cli-babel": "^5.1.5", "ember-cli-moment-shim": "1.1.0", "ember-cli-node-assets": "^0.1.3", - "ember-data-url-templates": "^0.1.1", "ember-get-config": "0.0.2", "ember-moment": "6.1.0", "ember-simple-auth": "1.1.0-beta.5", - "js-yaml": "^3.6.0", - "uri-templates": "^0.1.9" + "js-yaml": "^3.6.0" }, "ember-addon": { "configPath": "tests/dummy/config" From 86dff602c26997862e1716660feca51519691339 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 19:09:44 -0400 Subject: [PATCH 12/13] Fix broken tests I'd like a better way to unit test the extractAttributes behavior than splitting into a separate method; suggestions very welcome --- addon/adapters/application.js | 4 +- addon/serializers/application.js | 7 +++- tests/unit/serializers/application-test.js | 45 ++++++++++------------ 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/addon/adapters/application.js b/addon/adapters/application.js index 3a80a17ea..95a3a8b8f 100644 --- a/addon/adapters/application.js +++ b/addon/adapters/application.js @@ -10,10 +10,10 @@ export default DS.JSONAPIAdapter.extend(DataAdapterMixin, { namespace: config.OSF.apiNamespace, pathForType: Ember.String.pluralize, - buildURL() { + buildURL(modelName, id, snapshot, requestType, query) { // jshint ignore:line var url = this._super(...arguments); // TODO: Is this still necessary? - if (!url.endsWith('/')) { + if (url.lastIndexOf('/') !== 0) { url += '/'; } return url; diff --git a/addon/serializers/application.js b/addon/serializers/application.js index bed8dbf8c..89ab966f3 100644 --- a/addon/serializers/application.js +++ b/addon/serializers/application.js @@ -9,7 +9,7 @@ export default DS.JSONAPISerializer.extend({ embeds: {serialize: false} }, - extractAttributes(modelClass, resourceHash) { + _mergeFields(resourceHash) { // ApiV2 `links` exist outside the attributes field; make them accessible to the data model if (resourceHash.links) { // TODO: Should also test whether model class defines a links field resourceHash.attributes.links = resourceHash.links; @@ -17,6 +17,11 @@ export default DS.JSONAPISerializer.extend({ if (resourceHash.embeds) { resourceHash.attributes.embeds = resourceHash.embeds; } + return resourceHash; + }, + + extractAttributes(modelClass, resourceHash) { + resourceHash = this._mergeFields(resourceHash); return this._super(modelClass, resourceHash); }, diff --git a/tests/unit/serializers/application-test.js b/tests/unit/serializers/application-test.js index ae5fc74a9..77ab6a77c 100644 --- a/tests/unit/serializers/application-test.js +++ b/tests/unit/serializers/application-test.js @@ -5,38 +5,35 @@ moduleForModel('base', 'Unit | Serializer | application', { needs: ['serializer:application'] }); -test('#_normalizeRecord adds links to attributes if included in payload', function(assert) { +test('#_mergeFields adds links to attributes if included in payload', function(assert) { let payload = { - id: faker.random.uuid(), - type: 'base', - attributes: { - key: 'value' - }, - links: { - html: faker.internet.url() - } + id: faker.random.uuid(), + type: 'base', + attributes: { + key: 'value' + }, + links: { + html: faker.internet.url() + } }; - let serializer = this.container.lookup('serializer:application'); - let normalized = serializer._normalizeRecord(payload); - + let normalized = serializer._mergeFields(payload); assert.equal(normalized.attributes.links, payload.links); }); -test('#_normalizeRecord adds links to attributes if included in payload', function(assert) { +test('#_mergeFields adds embeds to attributes if included in payload', function(assert) { let payload = { - id: faker.random.uuid(), - attributes: { - key: 'value' - }, - embeds: { - embedded: { - data: [faker.random.arrayElement()] - } - } + id: faker.random.uuid(), + attributes: { + key: 'value' + }, + embeds: { + embedded: { + data: [faker.random.arrayElement()] + } + } }; - let serializer = this.container.lookup('serializer:application'); - let normalized = serializer._normalizeRecord(payload); + let normalized = serializer._mergeFields(payload); assert.equal(normalized.attributes.embeds, payload.embeds); }); From dc60e1f37a63cd5411d86006c2ed6b5c189e9aa1 Mon Sep 17 00:00:00 2001 From: Andy Boughton Date: Tue, 10 May 2016 19:16:38 -0400 Subject: [PATCH 13/13] Clean up todo --- addon/adapters/application.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/adapters/application.js b/addon/adapters/application.js index 95a3a8b8f..cff7dd94b 100644 --- a/addon/adapters/application.js +++ b/addon/adapters/application.js @@ -12,7 +12,8 @@ export default DS.JSONAPIAdapter.extend(DataAdapterMixin, { buildURL(modelName, id, snapshot, requestType, query) { // jshint ignore:line var url = this._super(...arguments); - // TODO: Is this still necessary? + // Fix issue where CORS request failed on 301s: Ember does not seem to append trailing + // slash to URLs for single documents, but DRF redirects to force a trailing slash if (url.lastIndexOf('/') !== 0) { url += '/'; }