From a14cbdd2771e9acfe41476fae51f6e3169fc6e25 Mon Sep 17 00:00:00 2001 From: Vlad Filippov Date: Thu, 23 Oct 2014 19:15:23 -0400 Subject: [PATCH] feat(update): better updating to clients, docs --- CONTRIBUTING.md | 79 ++++++++++++++++++++++++++ README.md | 18 +++--- app/adapters/application.js | 79 +++++++++++++++++++++----- app/controllers/client/update.js | 9 +++ app/controllers/clients.js | 10 ++++ app/initializers/application.js | 1 + app/initializers/authentication.js | 43 +++++++++++--- app/routes/client/index.js | 19 +++++++ app/routes/client/update.js | 15 ++++- app/routes/clients.js | 2 - app/styles/app.scss | 12 ++++ app/templates/client/index.hbs | 61 ++++++++++++++------ app/templates/clients.hbs | 11 ++-- lib/routes/oauth.js | 4 +- package.json | 1 - tests/unit/controllers/clients-test.js | 15 +++++ 16 files changed, 323 insertions(+), 56 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 app/controllers/client/update.js create mode 100644 app/controllers/clients.js create mode 100644 app/routes/client/index.js create mode 100644 tests/unit/controllers/clients-test.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5bf435a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,79 @@ +# Contributing + +Anyone is welcome to help with Firefox Accounts. Feel free to get in touch with other community members on IRC, the +mailing list or through issues here on GitHub. + +- IRC: `#fxa` on `irc.mozilla.org` +- Mailing list: +- and of course, [the issues list](https://github.com/mozilla/fxa-oauth-server/issues) + +## Bug Reports ## + +You can file issues here on GitHub. Please try to include as much information as you can and under what conditions +you saw the issue. + +## Sending Pull Requests ## + +Patches should be submitted as pull requests (PR). + +Before submitting a PR: +- Your code must run and pass all the automated tests before you submit your PR for review. "Work in progress" pull requests are allowed to be submitted, but should be clearly labeled as such and should not be merged until all tests pass and the code has been reviewed. + - Run `npm test` to make sure all tests still pass and there are no lint errors. +- Your patch should include new tests that cover your changes. It is your and your reviewer's responsibility to ensure your patch includes adequate tests. + +When submitting a PR: +- You agree to license your code under the project's open source license ([MPL 2.0](/LICENSE)). +- Base your branch off the current `master` (see below for an example workflow). +- Add both your code and new tests if relevant. +- Run `grunt jshint` and `npm test` to make sure your code passes linting and tests. +- Please do not include merge commits in pull requests; include only commits with the new relevant code. + +See the main [README.md](/README.md) for information on prerequisites, installing, running and testing. + +## Code Review ## + +This project is production Mozilla code and subject to our [engineering practices and quality standards](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Committing_Rules_and_Responsibilities). Every patch must be peer reviewed. This project is part of the [Firefox Accounts module](https://wiki.mozilla.org/Modules/Other#Firefox_Accounts), and your patch must be reviewed by one of the listed module owners or peers. + +## Example Workflow ## + +This is an example workflow to make it easier to submit Pull Requests. Imagine your username is `user1`: + +1. Fork this repository via the GitHub interface + +2. The clone the upstream (as origin) and add your own repo as a remote: + + ```sh + $ git clone https://github.com/mozilla/fxa-oauth-console.git + $ cd fxa-oauth-console + $ git remote add user1 git@github.com:user1/fxa-oauth-console.git +``` + +3. Create a branch for your fix/feature and make sure it's your currently checked-out branch: + + ```sh + $ git checkout -b add-new-feature +``` + +4. Add/fix code, add tests then commit and push this branch to your repo: + + ```sh + $ git add + $ git commit + $ git push user1 add-new-feature +``` + +5. From the GitHub interface for your repo, click the `Review Changes and Pull Request` which appears next to your new branch. + +6. Click `Send pull request`. + +### Keeping up to Date ### + +The main reason for creating a new branch for each feature or fix is so that you can track master correctly. If you need +to fetch the latest code for a new fix, try the following: + +```sh +$ git checkout master +$ git pull +``` + +Now you're ready to branch again for your new feature (from step 3 above). \ No newline at end of file diff --git a/README.md b/README.md index 7e7900e..c5059ec 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## Development -Installation: +Install: ``` git clone https://github.com/mozilla/fxa-oauth-console @@ -13,18 +13,20 @@ cd fxa-oauth-console npm install ``` -Running tests: - -``` -npm test -``` - -Running the server locally: +Run development server locally: ``` npm start ``` +**You will need a local Firefox Accounts stack.** + +Run tests: + +``` +npm test +``` + ## License [MPL v2.0](LICENSE) diff --git a/app/adapters/application.js b/app/adapters/application.js index b016a97..7b0dbe4 100644 --- a/app/adapters/application.js +++ b/app/adapters/application.js @@ -15,49 +15,102 @@ export default DS.RESTAdapter.extend({ * API Host */ host: config.servers.oauth, + /** + * Request headers + * + * Sets Authorization headers + */ headers: Ember.computed(function () { return { 'Authorization': 'Bearer ' + this.get('session.content.token') }; }), + /** + * Overrides default RESTAdapter 'find'. + * + * @param store + * @param type + * @param id + * @param record + * @returns {*} + */ find: function(store, type, id, record) { + // post process the resuld of 'find'. Need to add the Model type 'client' into the response return this.ajax(this.buildURL(type.typeKey, id, record), 'GET').then(function (resp) { - resp.id = id; - return { client: resp }; }); }, + /** + * Overrides default RESTAdapter 'createRecord' + * + * @param store + * @param type + * @param record + * @returns {*} + */ createRecord: function(store, type, record) { var data = {}; var serializer = store.serializerFor(type.typeKey); serializer.serializeIntoHash(data, type, record, { includeId: true }); + // post process the resuld of 'find'. Need to add the Model type 'client' into the response return this.ajax(this.buildURL(type.typeKey, null, record), "POST", { data: data }).then(function (resp) { - - resp.id = resp.client_id; - delete resp.client_id; - return { client: resp }; }); }, - buildURL: function(type, id, record) { - var url = [], - host = this.host, - prefix = this.urlPrefix(); + /** + * Overrides default RESTAdapter 'updateRecord' + * @param store + * @param type + * @param record + * @returns {*} + */ + updateRecord: function(store, type, record) { + var data = {}; + var serializer = store.serializerFor(type.typeKey); + serializer.serializeIntoHash(data, type, record); + var id = record.id; + // set POST instead of PUT + return this.ajax(this.buildURL(type.typeKey, id, record), "POST", { data: data }).then(function () { + data.id = id; + + return { client: data }; + }); + }, + /** + /** + * Overrides default RESTAdapter 'buildURL'. + * @param type + * @param id + * @param record + * @returns {Array} + */ + buildURL: function(type, id, record) { + var url = []; + var host = this.host; + var prefix = this.urlPrefix(); + + // FxA OAuth API requires singular 'client' when the record id is set if (record) { url.push('client'); } else { url.push('clients'); } - if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); } + if (id && !Ember.isArray(id)) { + url.push(encodeURIComponent(id)); + } - if (prefix) { url.unshift(prefix); } + if (prefix) { + url.unshift(prefix); + } url = url.join('/'); - if (!host && url) { url = '/' + url; } + if (!host && url) { + url = '/' + url; + } return url; } diff --git a/app/controllers/client/update.js b/app/controllers/client/update.js new file mode 100644 index 0000000..f528bf4 --- /dev/null +++ b/app/controllers/client/update.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Ember from 'ember'; + +export default Ember.Controller.extend({ + needs: ['client'] +}); diff --git a/app/controllers/clients.js b/app/controllers/clients.js new file mode 100644 index 0000000..5b4829a --- /dev/null +++ b/app/controllers/clients.js @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Ember from 'ember'; + +export default Ember.Controller.extend({ + sortProperties: ['name'], + sortAscending: true +}); diff --git a/app/initializers/application.js b/app/initializers/application.js index aa88b77..bcc8188 100644 --- a/app/initializers/application.js +++ b/app/initializers/application.js @@ -6,6 +6,7 @@ import Ember from 'ember'; export var initialize = function(container, application) { Ember.A(['adapter', 'controller', 'route']).forEach(function(component) { + // inject session into adapters, controllers and routes application.inject(component, 'session', 'simple-auth-session:main'); }); }; diff --git a/app/initializers/authentication.js b/app/initializers/authentication.js index 8b5e305..c443226 100644 --- a/app/initializers/authentication.js +++ b/app/initializers/authentication.js @@ -5,9 +5,21 @@ import Ember from 'ember'; import Base from 'simple-auth/authenticators/base'; +/** + * Custom Ember Simple Auth Authenticator + * See docs: http://ember-simple-auth.simplabs.com/ember-simple-auth-api-docs.html + */ var CustomAuthenticator = Base.extend({ + /** + * Token endpoint + */ tokenEndpoint: '/oauth', - + /** + * Restores application session data + * + * @param data + * @returns {Rx.Promise} + */ restore: function(data) { return new Ember.RSVP.Promise(function(resolve, reject) { if (!Ember.isEmpty(data.token)) { @@ -18,6 +30,11 @@ var CustomAuthenticator = Base.extend({ }); }, + /** + * Authenticate the user using the server side endpoint + * + * @returns {Rx.Promise} + */ authenticate: function () { var _this = this; @@ -27,35 +44,46 @@ var CustomAuthenticator = Base.extend({ type: 'GET', contentType: 'application/json' }).then(function (response) { - response = JSON.parse(response); + try { + response = JSON.parse(response); + } catch (e) { + return reject(e); + } Ember.run(function () { - if (response && response.email && response.token) { + if (response && response.email && response.token && response.code) { return resolve({ + code: response.code, email: response.email, token: response.token }); } else { - return reject(); + return reject('Respose missing credential data.'); } }); }, function (xhr/*, status, error*/) { var response = xhr.responseText; + try { response = JSON.parse(xhr.responseText); } catch (e) { - + return reject(); } Ember.run(function () { - reject(response.error); + return reject(response.error); }); }); }); }, + /** + * Invalidates the user session on the server + * + * @returns {Rx.Promise} + */ invalidate: function () { var _this = this; @@ -73,7 +101,8 @@ var CustomAuthenticator = Base.extend({ export default { name: 'authentication', before: 'simple-auth', - initialize: function (container/*, application*/) { + initialize: function (container) { + // registers the custom authenticator container.register('authenticator:custom', CustomAuthenticator); } }; diff --git a/app/routes/client/index.js b/app/routes/client/index.js new file mode 100644 index 0000000..daa50b9 --- /dev/null +++ b/app/routes/client/index.js @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import Ember from 'ember'; +import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; + +export default Ember.Route.extend(AuthenticatedRouteMixin, { + actions: { + update: function (model) { + this.transitionTo('client.update', model); + }, + remove: function (id) { + return this.store.find('client', id).then(function (client) { + client.destroyRecord(); + }); + } + } +}); diff --git a/app/routes/client/update.js b/app/routes/client/update.js index a6892c0..d6417a8 100644 --- a/app/routes/client/update.js +++ b/app/routes/client/update.js @@ -5,4 +5,17 @@ import Ember from 'ember'; import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; -export default Ember.Route.extend(AuthenticatedRouteMixin, {}); +export default Ember.Route.extend(AuthenticatedRouteMixin, { + actions: { + update: function(model) { + var _this = this; + + return model.save().then(function () { + _this.transitionTo('client.index', model.id); + }); + }, + cancel: function() { + return this.transitionTo('clients'); + } + } +}); diff --git a/app/routes/clients.js b/app/routes/clients.js index c84f7b0..365cc87 100644 --- a/app/routes/clients.js +++ b/app/routes/clients.js @@ -28,9 +28,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { this.transitionTo('clients'); }, remove: function (id) { - console.log(id); return this.store.find('client', id).then(function (client) { - console.log(client); client.destroyRecord(); }); }, diff --git a/app/styles/app.scss b/app/styles/app.scss index ec76cd5..72517d3 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -51,6 +51,18 @@ .table { width: 100%; + &.table-clients { + a { + font-weight: bold; + font-size: 20px; + padding: 10px 0; + display: block; + } + } + td.table-actions { + width: 25%; + text-align: center; + } } diff --git a/app/templates/client/index.hbs b/app/templates/client/index.hbs index 985fdf2..e3bb753 100644 --- a/app/templates/client/index.hbs +++ b/app/templates/client/index.hbs @@ -1,19 +1,46 @@ -
- - +

OAuth Client: {{name}}

+ + + + + + + + + + + + + + + + + + + + +
Client ID:{{id}}
Redirect URI{{redirect_uri}}
Image URI{{image_uri}}
Client Secret + +
+ +
+
+
    +
  • + {{#link-to 'clients' classNames="small button success"}}< Back to Clients{{/link-to}} +
  • +
+
+
+
    +
  • + +
  • +
  • + +
  • +
+
-
- - {{name}} -
- -
- - {{redirect_uri}} -
- -
- - {{image_uri}} -
+{{outlet}} diff --git a/app/templates/clients.hbs b/app/templates/clients.hbs index 8e729fa..85aebee 100644 --- a/app/templates/clients.hbs +++ b/app/templates/clients.hbs @@ -1,19 +1,18 @@ - +
- +
- {{#each client in content}} - - + - diff --git a/lib/routes/oauth.js b/lib/routes/oauth.js index 7e06621..ad28865 100644 --- a/lib/routes/oauth.js +++ b/lib/routes/oauth.js @@ -33,7 +33,8 @@ router.get('/status', function (req, res) { if (req.session && req.session.email) { return res.send(JSON.stringify({ email: req.session.email, - token: req.session.token + token: req.session.token, + code: req.session.code })); } else { return res.status(401).end(); @@ -81,6 +82,7 @@ router.get('/redirect', function (req, res) { } log.verbose(err, body); + req.session.code = code; req.session.scopes = body.scopes; req.session.token_type = body.token_type; var token = req.session.token = body.access_token; diff --git a/package.json b/package.json index e248571..b1b799f 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ }, "devDependencies": { "ember-cli": "0.1.2", - "ember-cli-inject-live-reload": "^1.3.0", "ember-cli-qunit": "0.1.0", "grunt": "^0.4.5", "grunt-cli": "^0.1.13", diff --git a/tests/unit/controllers/clients-test.js b/tests/unit/controllers/clients-test.js new file mode 100644 index 0000000..86bbdd7 --- /dev/null +++ b/tests/unit/controllers/clients-test.js @@ -0,0 +1,15 @@ +import { + moduleFor, + test +} from 'ember-qunit'; + +moduleFor('controller:clients', 'ClientsController', { + // Specify the other units that are required for this test. + // needs: ['controller:foo'] +}); + +// Replace this with your real tests. +test('it exists', function() { + var controller = this.subject(); + ok(controller); +});
ID Name Redirect URI
{{client.id}}{{client.name}}{{client.name}}{{client.id}} {{client.redirect_uri}} + +