Skip to content

Commit

Permalink
Merge branch 'release/18.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
jamescdavis committed Nov 29, 2018
2 parents c313993 + 739a2f5 commit 86e7343
Show file tree
Hide file tree
Showing 87 changed files with 1,456 additions and 211 deletions.
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [18.2.0] - 2018-11-29
### Changed
- Components:
- `sign-up-form` - Distinguish between alrteady registered and invalid (e.g. blacklisted) emails
- Models:
- `user-registration` - added invalid email validation and `addInvalidEmail` method
- Routes:
- `register` - let CAS redirect to ORCID

## [18.1.2] - 2018-11-05
- Engines:
- `registries/discover` - reset to first page on user search input
Expand All @@ -18,10 +27,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- Components:
- `panel` - a general-use abstraction of bootstrap panels
- `validated-model-form` - wraps common logic for forms made with `validated-input/*`
- Tests:
- `panel` component integration test
- Handbook:
- `panel` component
- Mirage:
- `node` POST view to add currentUser as contributor
- `regions` fixtures
- `wb` view to move files from user or node to a node
- Routes:
- `settings.applications` - list of developer apps
- `settings.applications.edit`
- `settings.applications.create`

### Changed
- Components:
- `loading-indicator` - added inline option
Expand All @@ -31,6 +50,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `loading-indicator` - added tests for inline
- Handbook:
- `loading-indicator` - added examples for inline
- Mirage:
- `root` factory now adds all feature flags, not just route flags
- `user` factory has 'withFiles' trait so non-current users can have files easily
- `user` serializer has default_region relationship (hardcoded to us)

### Removed
- Flags:
- `ember_project_forks_page` - `guid-node.forks` and `guid-registration.forks` now always on
Expand All @@ -42,6 +66,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `registration-schema` (including related adapter & serializer)
- `token`
- `scope`
- `developer-app`
- Components:
- `search-help-modal` - you know, the search help modal but as it's own component
- `draft-registration-card` - summary card for draft registrations
Expand All @@ -54,7 +79,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `delete-button` - configurable delete button, including a confirmation modal and scientist name
- `tags-widget` - you know, for tags
- Routes:
- `guid-node/registrations` - registrations tab
- `guid-node.registrations` - registrations tab
- `settings` - includes the settings side nav
- `settings/tokens` - list of personal access tokens
- `settings/tokens/edit`
Expand Down
13 changes: 13 additions & 0 deletions app/adapters/developer-app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import OsfAdapter from './osf-adapter';

export default class DeveloperAppAdapter extends OsfAdapter {
pathForType(_: string) {
return 'applications';
}
}

declare module 'ember-data' {
interface AdapterRegistry {
'developer-app': DeveloperAppAdapter;
}
}
39 changes: 38 additions & 1 deletion app/locales/en/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export default {
component: 'component',
hosted_on_the_osf: 'Hosted on OSF',
please_confirm: 'Please confirm',
required: 'Required',
optional: 'Optional',
},
maintenance: {
line1: 'The site will undergo maintenance between <strong>{{start}} and {{end}}</strong> ({{utc}} UTC).',
Expand Down Expand Up @@ -443,6 +445,7 @@ export default {
url: '{{description}} must be a valid url.',
// custom
email_registered: 'This email address has already been registered.',
email_invalid: 'Invalid email address. If this should not have occurred, please report this to {{supportEmail}}',
email_match: 'Email addresses must match.',
password_email: 'Your password cannot be the same as your email address.',
password_old: 'Your new password cannot be the same as your old password.',
Expand Down Expand Up @@ -1102,6 +1105,7 @@ export default {
modalTitle: 'Are you sure you want to delete this?',
modalBody: 'This action is irreversible.',
hardConfirm: 'Type the following to continue: <strong>{{text}}</strong>',
error: 'There was an error deleting this item.',
},
'paginated-list': {
error: 'There was an error loading this list.',
Expand Down Expand Up @@ -1137,8 +1141,38 @@ export default {
notifications: {
title: 'Notifications',
},
apps: {
'developer-apps': {
title: 'Developer apps',
explanation: 'The OSF allows third-party web applications to connect to the OSF on behalf of other users via the OAuth 2.0 web application flow.',
createApp: 'Create developer app',
backToList: 'Back to list of developer apps',
appDetail: 'Detail for app <strong>{{appName}}</strong>',
editApp: 'Edit app',
appName: 'App name',
appHomepage: 'Project homepage URL',
appDescription: 'App description',
appCallbackUrl: 'Authorization callback URL',
clientID: 'Client ID',
clientIDDescription: 'The unique identifier for this developer app. It is safe to share publicly with others.',
clientSecret: 'Client secret',
clientSecretDescription: 'The client secret is known only to you and OSF. Do not display or expose it to others.',
showSecret: 'Show client secret',
hideSecret: 'Hide client secret',
created: 'Developer app created.',
saved: 'Developer app saved.',
deleted: 'Developer app deleted.',
resetSecret: {
label: 'Reset secret',
description: 'Resetting the client secret will render your application unusable until it is updated with the new client secret, and all users must reauthorize access. Previously issued access tokens will no longer work.',
modalTitle: 'Reset client secret?',
confirm: 'Are you sure you want to reset the client secret? This cannot be reversed.',
success: 'Client secret successfully reset.',
error: 'Error resetting client secret.',
},
confirmDelete: {
title: 'Delete app <strong>{{appName}}</strong>?',
body: 'Are you sure you want to delete this developer app? All users\' access tokens will be revoked. This cannot be reversed.',
},
},
tokens: {
title: 'Personal access tokens',
Expand All @@ -1149,6 +1183,9 @@ export default {
tokenName: 'Token name',
scopes: 'Scopes',
scopesDescription: 'Scopes limit access for personal access tokens.',
created: 'Token created.',
saved: 'Token saved.',
deleted: 'Token deleted.',
confirmDelete: {
title: 'Delete token <strong>{{tokenName}}</strong>?',
body: 'Are you sure you want to delete this personal access token? This cannot be reversed.',
Expand Down
70 changes: 70 additions & 0 deletions app/models/developer-app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { attr } from '@ember-decorators/data';
import { buildValidations, validator } from 'ember-cp-validations';

import { Document as ApiResponseDocument } from 'osf-api';
import OsfModel from './osf-model';

const Validations = buildValidations({
name: [
validator('presence', true),
validator('length', { min: 1, max: 200 }),
],
homeUrl: [
validator('presence', true),
validator('length', { min: 1, max: 200 }),
validator('format', { type: 'url' }),
],
description: [
validator('length', { min: 0, max: 1000 }),
],
callbackUrl: [
validator('presence', true),
validator('length', { min: 1, max: 200 }),
validator('format', { type: 'url' }),
],
});

export default class DeveloperAppModel extends OsfModel.extend(Validations) {
@attr() callbackUrl!: string;
@attr() clientId!: string;
@attr() clientSecret!: string;
@attr('date') dateCreated!: Date;
@attr({ defaultValue: '' }) description!: string;
@attr() homeUrl!: string;
@attr() name!: string;
@attr() owner!: string;

// TODO (EMB-407) When the API is updated, remove this method and reset the secret
// by PATCHing `clientSecret` to `null`
async resetSecret(): Promise<void> {
const resetUrl = this.links.reset;
const adapter = this.store.adapterFor('developer-app');
const serializer = this.store.serializerFor('developer-app');

// @ts-ignore -- Private API
const snapshot = this._createSnapshot();

const response: ApiResponseDocument = await adapter.ajax(resetUrl, 'POST', {
data: serializer.serialize(snapshot, {
includeId: true,
osf: {
includeCleanData: true,
},
}),
});

if ('data' in response && 'id' in response.data) {
this.store.pushPayload('developer-app', response);
} else if ('errors' in response) {
throw new Error(response.errors.map(error => error.detail).join('\n'));
} else {
throw new Error('Unexpected response while resetting client secret for developer app');
}
}
}

declare module 'ember-data' {
interface ModelRegistry {
'developer-app': DeveloperAppModel;
}
}
21 changes: 18 additions & 3 deletions app/models/user-registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@ import { attr } from '@ember-decorators/data';
import { computed } from '@ember/object';
import { buildValidations, validator } from 'ember-cp-validations';
import DS from 'ember-data';
import config from 'ember-get-config';

const { Model } = DS;

const { support: { supportEmail } } = config;

const Validations = buildValidations({
email1: [
validator('presence', true),
validator('format', { type: 'email' }),
validator('exclusion', {
messageKey: 'validationErrors.email_registered',
in: computed(function(): string[] {
return [...this.get('model').get('existingEmails')];
return [...this.model.existingEmails];
}).volatile(),
}),
validator('exclusion', {
messageKey: 'validationErrors.email_invalid',
supportEmail,
in: computed(function(): string[] {
return [...this.model.invalidEmails];
}).volatile(),
}),
validator('length', {
Expand Down Expand Up @@ -71,9 +81,14 @@ export default class UserRegistration extends Model.extend(Validations) {
@attr('boolean') acceptedTermsOfService!: boolean;

existingEmails: Set<string> = new Set();
invalidEmails: Set<string> = new Set();

addExistingEmail(email?: string) {
this.existingEmails.add(email || this.email1);
}

addExistingEmail(this: UserRegistration, email?: string) {
this.get('existingEmails').add(email || this.get('email1'));
addInvalidEmail(email?: string) {
this.invalidEmails.add(email || this.email1);
}
}

Expand Down
15 changes: 8 additions & 7 deletions app/register/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ import config from 'ember-get-config';
import Analytics from 'ember-osf-web/services/analytics';
import param from 'ember-osf-web/utils/param';

const { OSF: { casUrl, orcidClientId, url: baseUrl } } = config;
const { OSF: { casUrl, url: baseUrl } } = config;

export default class Register extends Controller {
queryParams = ['next'];
next?: string;

@service analytics!: Analytics;

orcidUrl = `https://www.orcid.org/oauth/authorize?${param({
client_id: orcidClientId || '',
scope: '/authenticate',
response_type: 'code',
redirect_uri: `${casUrl}/login?client_name=OrcidClient#show_login`,
})}`;
@computed('next')
get orcidUrl() {
return `${casUrl}/login?${param({
redirectOrcid: 'true',
service: `${baseUrl}/login/?next=${encodeURIComponent(this.next || baseUrl)}`,
})}`;
}

@computed('next')
get institutionUrl() {
Expand Down
2 changes: 1 addition & 1 deletion app/register/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<div local-class="sign-up-buttons" class="m-md">
<a
data-test-orcid-button
href={{orcidUrl}}
href="{{orcidUrl}}#show_login"
local-class="sign-up-button"
onclick={{action "click" "button" "Sign up - ORCID" target=analytics}}
>
Expand Down
4 changes: 4 additions & 0 deletions app/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ Router.map(function() {
this.route('quickfiles');
this.route('register');
this.route('settings', function() {
this.route('developer-apps', { path: '/applications' }, function() {
this.route('edit', { path: '/:developer_app_id' });
this.route('create');
});
this.route('tokens', function() {
this.route('edit', { path: '/:token_id' });
this.route('create');
Expand Down
21 changes: 21 additions & 0 deletions app/serializers/developer-app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import OsfSerializer from './osf-serializer';

export default class DeveloperAppSerializer extends OsfSerializer {
attrs: any = {
// eslint-disable-next-line ember/no-attrs-in-components
...this.attrs, // from OsfSerializer

clientSecret: {
serialize: false,
},
clientId: {
serialize: false,
},
};
}

declare module 'ember-data' {
interface SerializerRegistry {
'developer-app': DeveloperAppSerializer;
}
}
3 changes: 2 additions & 1 deletion app/serializers/file-provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ModelRegistry } from 'ember-data';
import OsfSerializer from './osf-serializer';

export default class FileProvider extends OsfSerializer {
modelNameFromPayloadKey(): string {
modelNameFromPayloadKey(): keyof ModelRegistry {
return 'file-provider';
}
}
Expand Down
Loading

0 comments on commit 86e7343

Please sign in to comment.