Skip to content
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
6 changes: 3 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
19 changes: 12 additions & 7 deletions addon/adapters/application.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import Ember from 'ember';
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
import UrlTemplates from "ember-data-url-templates";

import config from 'ember-get-config';

export default DS.JSONAPIAdapter.extend(UrlTemplates, DataAdapterMixin, {
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:osf-token',
host: config.OSF.apiUrl,
urlTemplate: '{+host}{modelName}{/id}/',
urlSegments: {
modelName (modelName) {
return Ember.String.pluralize(modelName);
}
namespace: config.OSF.apiNamespace,
pathForType: Ember.String.pluralize,

buildURL(modelName, id, snapshot, requestType, query) { // jshint ignore:line
var url = this._super(...arguments);
// 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 += '/';
}
return url;
}
});
2 changes: 1 addition & 1 deletion addon/authenticators/osf-token.js
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
3 changes: 2 additions & 1 deletion addon/mixins/osf-login-route.js
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shameless copy/paste. Will remove during merge.

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) {
Expand Down
2 changes: 1 addition & 1 deletion addon/models/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
});
60 changes: 31 additions & 29 deletions addon/serializers/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,41 @@ 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;

// 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}
},
_normalizeRecord(record) {
record.attributes = this._normalizeAttributes(record.attributes);
if (record.links) {
record.attributes.links = record.links;
}
if (record.embeds) {
// TODO, actually merge in embedded data?
record.attributes.embeds = record.embeds;
}
return record;
},
normalizeSingleResponse(_, __, payload) {
payload.data = this._normalizeRecord(payload.data);
return this._super(...arguments);

_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;
}
if (resourceHash.embeds) {
resourceHash.attributes.embeds = resourceHash.embeds;
}
return resourceHash;
},
normalizeArrayResponse(_, __, payload) {
payload.data = payload.data.map(this._normalizeRecord.bind(this));
return this._super(...arguments);

extractAttributes(modelClass, resourceHash) {
resourceHash = this._mergeFields(resourceHash);
return this._super(modelClass, resourceHash);
},
keyForAttribute(key) {
return Ember.String.camelize(key);

keyForAttribute(key, method) {
if (method === 'deserialize') {
return Ember.String.underscore(key);
} else if (method === 'serialize') {
return Ember.String.camelize(key);
}
},

serializeIntoHash(/*hash, typeClass, snapshot, options*/) {
// Don't send links as part of hash
// TODO
return this._super(...arguments);
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;
}
});
81 changes: 36 additions & 45 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,46 @@ 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/<hostname>.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/<hostname>.yml`);
}

ENV.OSF = {
clientId: SETTINGS.CLIENT_ID,
scope: SETTINGS.OAUTH_SCOPES
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/v2/';
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.isLocal = true;
}
if (BACKEND === 'stage') {
ENV.OSF.url = 'https://staging.osf.io/';
ENV.OSF.apiUrl = 'https://staging-api.osf.io/v2/';
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/v2/';
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/v2/';
ENV.OSF.authUrl = 'https://accounts.osf.io/oauth2/authorize';
}

ENV['ember-simple-auth'] = {
authorizer: 'authorizer:osf-token'
ENV.OSF.accessToken = SETTINGS.PERSONAL_ACCESS_TOKEN;
ENV.OSF.isLocal = 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') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably shouldn't condone using prod as a backend for local development. If a dev needs a prod-like backend, they should use test.osf.io.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloria agreed, and I am trying to get the README to reflect this (we can be more explicit too), but the code should not assume that it's never being run in production.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding support for the test backend got lost in the shuffle, but I agree it should be added for use by third-party integrators. Thanks for the reminder!

Presumably, prod is kept for use in deployment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samchrisinger As discussed in our other thread, envvars should be used for production and any non-local deploys.

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'
};
},
// A small hack for ember-data-url-templates to work
// TODO: followup based on https://github.com/dfreeman/ember-cli-node-assets/issues/1
options: {
nodeAssets: {
'uri-templates': {
import: ['uri-templates.js']
}
}
}
};
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
Expand Down
20 changes: 14 additions & 6 deletions tests/dummy/app/routes/nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
session: Ember.inject.service(),
model() {
let user = this.modelFor('application');
if(user) {
return user.get('nodes');
}
else {
return this.get('store').findRecord('user', 'me').then(user => user.get('nodes'));
}
if (user) {
return user.get('nodes'); // Fetch from `/users/me/nodes/`
}
else {
return this.get('store').findRecord('user', 'me').then(user => user.get('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();
}
}
});
22 changes: 21 additions & 1 deletion tests/dummy/app/routes/nodes/detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ 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);
},

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');
}
}
}

});
2 changes: 1 addition & 1 deletion tests/dummy/app/templates/application.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="container-fluid">
{{link-to 'Home' 'index' class="btn btn-default"}}
<h2 id="title">Welcome to OSF Ember Example App</h2>
<h1 id="title">Welcome to OSF Ember Example App</h1>
<div class="row">
<div class="col-md-12">
{{outlet}}
Expand Down
40 changes: 26 additions & 14 deletions tests/dummy/app/templates/nodes/detail.hbs
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
{{link-to 'Back to list' 'nodes' class="btn btn-default"}}
<div class="panel">
<p><label>Title: </label>{{model.title}}</p>
<p><label>Category: </label>{{model.category}}</p>
<p><label>Date Created: </label>{{moment-format model.dateCreated}}</p>
<p><label>Date Modified: </label>{{moment-format model.dateModified}}</p>

<h2>Data</h2>
<p><label>Title:</label> {{model.title}}</p>
<p><label>Category:</label> {{model.category}}</p>
<p><label>Date Created:</label> {{moment-format model.dateCreated}}</p>
<p><label>Date Modified:</label> {{moment-format model.dateModified}}</p>
<p>
<a href="{{model.links.html}}" target="_blank" class="btn btn-primary">
View on OSF
</a>
</p>
<hr>
<p>
<label>Contributors</label>
<p>

<h2>Contributors</h2>

<table class="table">
{{#each model.contributors as |contrib|}}
<tr>
{{contrib.bibliographic}}
</tr>
{{/each}}
<tr>
<th>ID</th>
<th>Author?</th>
</tr>
{{#each model.contributors as |contrib|}}
<tr>
<td>{{contrib.id}}</td>
<td>{{contrib.bibliographic}}</td>
</tr>
{{/each}}
</table>
</p>
</p>



<h2>Edit this node</h2>
Title: {{input value=editedTitle}}
<button {{action "editExisting" editedTitle}} class="btn btn-primary">Edit record</button>

</div>

Loading