Skip to content

Conversation

@binoculars
Copy link
Member

@binoculars binoculars commented Nov 29, 2016

See the spec for details.

Companion to:

Ticket

https://openscience.atlassian.net/browse/EOSF-327

TODO:

  • Make the routes under /preprints/:provider/:whatever redirect to provider.domain/:whatever
  • Update all redirects to go to the correct place, the first time (no multiple redirects, where possible).
  • Get tests passing
  • Provide guidance for staging and prod (Update: DevOps ticket in Jira)

Notes for Reviewers:

If testing this PR without the changes from OSF, set environment variable ENABLE_PROVIDER_DOMAINS='true'

See the README section on how to populate the domains locally. The domains are defined in the ember config (config/environment.js). TLDR: sudo ./scripts/add-domains.js

Notes for QA

  • This is mostly a code change with the exception of how the routing is handled. Once this is up on staging, all of the redirects should work as expected.

@binoculars binoculars changed the title [WIP] Feature/branding phase2 [WIP] Feature/branding phase2 [PREP-259] Nov 29, 2016
Created error-page component and migrated forbidden, page-not-found, and resource-deleted to use error-page component
Updated english translation to match error-component migration
Removed unused reroute-guid template
Update provider route to use the redirect if the domain exists in the configuration
Fix for asset loading in index.html\
Add translation with 'or' from index page
@binoculars binoculars force-pushed the feature/branding-phase2 branch from f2f9df6 to d238433 Compare January 30, 2017 21:30
@binoculars binoculars changed the title [WIP] Feature/branding phase2 [PREP-259] Branding Phase 2 - Provider Domains [PREP-259] Mar 13, 2017
Copy link
Contributor

@abought abought left a comment

Choose a reason for hiding this comment

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

This is not a complete review, but I have been called away to a number of Lookit tasks, and am submitting any notes so far "as is". No functional review has been performed yet.

Per discussion with Barrett today, first impressions are all around maintainability:

  • Please add a few short YUIDoc strings on helpers to help document specific requirements being met
  • Very strong preference for at least some tests. If we can fast track the factories PR, that would help with this. Maintainability is a challenge due to complexity of 4-state router requirements.
  • If possible, a CDN for css assets would help us avoid some of the scattered code for asset paths. May be out of scope for this PR but would help with maintainability.

},
application: {
// Nothing to translate
separator: ` | `
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this something we really need to expose to translations?

If the goal is only to DRY this code, consider using the ember-page-title addon config:
https://github.com/tim-evans/ember-page-title#api

const configProvider = providers.find(p => p.id === providerId);

if (!configProvider)
throw new Error('Provider is not configured properly. Check the Ember configuration.');
Copy link
Contributor

Choose a reason for hiding this comment

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

There does not appear to be any .catch statement associated with this promise. (aside from whatever ember will do internally if the afterModel hook returns a rejected promise)

  • Is this an error the user should be notified about?
  • If so, should there be a translation string here?

if (providerIds.includes(slugLower)) {
const {domain} = providers.find(provider => provider.id === slugLower) || {};

// This should be caught by the proxy, but we'll redirect just in case it is not.
Copy link
Contributor

Choose a reason for hiding this comment

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

Note to self: "the proxy" refers to nginx handling domain redirect (before it hits ember)

continue;

if (provider.id === 'osf') {
provider.domain = OSF_URL || 'localhost:5000';
Copy link
Contributor

Choose a reason for hiding this comment

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

Please try to avoid hardcoding URLs and ports wherever possible, and strongly prefer fetching config from pre-existing sources. (ember osf config should already provide an OSF URL, for example)

continue;
}

const suffix = DOMAIN_PREFIX ? '' : `:${PORT ? PORT : '4200'}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't seem to find a good way to determine port number, alas. At very least this could be shortened to PORT || '4200'.

But to be honest, that's bikeshedding over syntax. It seems like this code is trying to do a very large number of things simultaneously, which is inevitably going to add complexity.

assets: {
enabled: true,
content: `
<script>
Copy link
Contributor

Choose a reason for hiding this comment

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

Future suggestion:

Consider using a CDN to serve assets like CSS. That would save us from this code because we would not need ember to construct CSS urls.

(ember locally would serve normally, and in production builds we'd use a CDN)

May not be in scope for this PR, but strongly worth future consideration. cos.io, for example, is already moving in this direction. This is a common pattern and I think any deployment challenges would be very solvable with automated DevOps support.

This code is a constructed string: it will be hidden from any tooling or bugfixing/ validation, and it causes url logic to be in many different places. By putting these specific assets on a different domain, the asset path wouldn't depend on URL- a CDN or "static asset domain" would help us avoid the necessity for some very gnarly code, and sidestep a potential long-term maintainability issue.

guidPathPrefix: Ember.computed('isProvider', 'isDomain', 'id', function() {
let pathPrefix = '/';

if (!this.get('isDomain') && this.get('isProvider')) {
Copy link
Contributor

Choose a reason for hiding this comment

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

See note elsewhere on CDN possibilities to simplify this code.

@@ -0,0 +1,15 @@
import Ember from 'ember';

export default Ember.Helper.extend({
Copy link
Contributor

Choose a reason for hiding this comment

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

Per discussion- can you please add yuidoc comments to explain the purpose of this helper?

(eg driven by the requirements of the 4-state router)

{{#each pair as |subject|}}
<div class="col-xs-12 col-sm-6 subject-item {{if (get subjectTooltips subject.text) 'hint--bottom hint--large'}}" aria-label={{get subjectTooltips subject.text}}>
{{#link-to (if theme.isProvider 'provider.discover' 'discover') (query-params subjectFilter=subject.text) class='btn btn-primary p-sm' invokeAction=(action "click" "link" (concat 'Preprints - Index - Browse ' subject.text))}}
{{#link-to (route-prefix 'discover') (query-params subjectFilter=subject.text) class='btn btn-primary p-sm' invokeAction=(action "click" "link" (concat 'Preprints - Index - Browse ' subject.text))}}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a somewhat gnarly requirement. Have you taken a look at Route#renderTemplate? It seems to provide a way for one route to use the template or behavior of another. I'm not totally sure if it applies here, but might spark some ideas.

http://emberjs.com/api/classes/Ember.Route.html#method_renderTemplate

@@ -0,0 +1,48 @@
#!/usr/bin/env node
Copy link
Contributor

Choose a reason for hiding this comment

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

No review performed on this script in initial round.

.find(p =>
// Check if the hostname includes: the domain, the domain with dashes instead of periods, or just the id
hostname.includes(p.domain) ||
hostname.includes(p.domain.replace(/\./g, '-')) ||
Copy link
Contributor

Choose a reason for hiding this comment

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

When is this relevant, out of curiosity?

Copy link
Member Author

Choose a reason for hiding this comment

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

I had a conversation with @icereval a while back about how we might deploy this on staging/test. agrixiv-org.staging.osf.io was a likely naming scheme. Putting a dot in a subdomain creates another subdomain.

Copy link
Contributor

@hmoco hmoco left a comment

Choose a reason for hiding this comment

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

Quick-ish run through. Looks good, just have a few questions about some choices made here. Nice work!

this.route('content', {path: '/:preprint_id'});
this.route('discover');

if (provider) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does provider get recalculated properly when window.location changes? I would assume it does, since it works, but it seems weird that a const value changed would cause this Router.map to be rerun, assuming the preprint app is still a singleton across the different providers

Copy link
Member Author

Choose a reason for hiding this comment

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

Since changing the provider requires a full page reload, the entire app, including the router, will be evaluated each time.

session: Ember.inject.service(),

// If we're using a provider domain
isDomain: false,
Copy link
Contributor

@hmoco hmoco Mar 30, 2017

Choose a reason for hiding this comment

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

Not the biggest fan of this, could we possibly change it to something like hasDomain, isProvider, onProvider, onProviderDomain? Don't feel strongly about any of these, but was initially confused by isDomain (although the comment is super helpful)

pathPrefix += 'preprints/';

if (this.get('isProvider')) {
pathPrefix += `${this.get('id')}/`;
Copy link
Contributor

Choose a reason for hiding this comment

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

wait, just realized that there's also something called isProvider. When would isDomain and isProvider not both be the same?

Copy link
Member Author

Choose a reason for hiding this comment

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

Some of the providers will not use their own domain, and will stay under osf.io/preprints/whatever

isProvider is used to determine if the provider is OSF (for our default case) or not
isDomain is whether the provider is using a domain or not

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a case in which the provider being used has a domain but is not using it?

isProvider is true if, and only if, the current provider is not OSF?

Copy link
Member Author

Choose a reason for hiding this comment

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

If the domain exists in the config (and domains are enabled), then using the domain is used. It has to be one or the other due to the requirements.

Yes, isProvider basically means not OSF.

{{error-page
label='Forbidden'
translateKey='page-forbidden'
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Really like this!

const sectionFooter = '\n## /EMBER-PREPRINTS ##';
const rgx = new RegExp(`(?:${sectionHeader})(.|\\s)*(?:${sectionFooter})`, 'm');
const domainProviders = providers
.slice(1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Throughout this PR, there seems to be a lot of providers.slice(1). Is there any use for a separate config var that defines non-OSF providers?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was trying to avoid modifying the original config too much, which would have downstream changes--not ideal, but neither is creating a ton of merge conflicts if it can be avoided.

@hmoco
Copy link
Contributor

hmoco commented Mar 30, 2017

Functional testing looked good, although I was unable to test the redirect from /preprints/<provider> to provider domain.

@hmoco
Copy link
Contributor

hmoco commented Mar 30, 2017

Also, after reading through this, not really a request for a change, but a quick note for both future development and potential refactoring: our usage of the word provider seems to be incredibly broad, including OSF at times. It leads to slightly confusing code due to it not being descriptive or precise enough. @brianjgeiger, @binoculars any opinions on the matter or potential alternative language?

@binoculars
Copy link
Member Author

I got set up locally and updated my osf.io PR. I would like avoid updating that again until we're serious about merging, because it needs a migration.

My local copy is redirecting, so I'm not sure what's causing it to not redirect. It could be a container sync issue.

I would like to come up with better semantics for provider. At this point, we've been using it in branded preprints since that was launched, so a refactor would need to be planned out.

@brianjgeiger
Copy link
Contributor

I think in the OSF world, a Provider is a third party that has information, code, or service that is being served via the OSF but is not generally available to everyone. So Users aren't Providers because anyone can be a user, but PreprintProvider, AddonProvider, RegistryProvider, and so on would be valid Providers (whether or not all of those things currently exist). Do we have uses that are not currently following that convention?

@binoculars
Copy link
Member Author

I'm not aware of any, but it would good to codify that somwhere

@brianjgeiger brianjgeiger merged commit 1ec026f into CenterForOpenScience:develop Apr 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants