From a39dc37a05a9ed51e6ead1abd90375dfdaa23d3a Mon Sep 17 00:00:00 2001
From: Jure Triglav <juretriglav@gmail.com>
Date: Wed, 22 Jul 2020 11:16:16 +0200
Subject: [PATCH] chore: move journal config to a single place

---
 app/config/journal/article-sections.js        |  30 --
 app/config/journal/declarations.js            | 101 -----
 app/config/journal/editors.js                 |  32 --
 app/config/journal/index.js                   |  12 -
 app/config/journal/metadata.js                |   4 -
 app/config/journal/review-status.js           |   1 -
 config/authsome.js                            | 350 ++++--------------
 config/default.js                             |  20 +-
 config/development.js                         |  10 +-
 .../journal/article-types.js                  |   2 +-
 {app/config => config}/journal/decisions.js   |   2 +-
 config/journal/index.js                       |  11 +
 config/journal/metadata.js                    |   4 +
 .../journal/recommendations.js                |   2 +-
 config/journal/review-status.js               |   1 +
 {app/config => config}/journal/roles.js       |   2 +-
 {app/config => config}/journal/sections.js    |   2 +-
 .../config => config}/journal/submit-notes.js |   2 +-
 .../journal/supplementary.js                  |   2 +-
 19 files changed, 111 insertions(+), 479 deletions(-)
 delete mode 100644 app/config/journal/article-sections.js
 delete mode 100644 app/config/journal/declarations.js
 delete mode 100644 app/config/journal/editors.js
 delete mode 100644 app/config/journal/index.js
 delete mode 100644 app/config/journal/metadata.js
 delete mode 100644 app/config/journal/review-status.js
 rename {app/config => config}/journal/article-types.js (93%)
 rename {app/config => config}/journal/decisions.js (96%)
 create mode 100644 config/journal/index.js
 create mode 100644 config/journal/metadata.js
 rename {app/config => config}/journal/recommendations.js (91%)
 create mode 100644 config/journal/review-status.js
 rename {app/config => config}/journal/roles.js (87%)
 rename {app/config => config}/journal/sections.js (76%)
 rename {app/config => config}/journal/submit-notes.js (97%)
 rename {app/config => config}/journal/supplementary.js (84%)

diff --git a/app/config/journal/article-sections.js b/app/config/journal/article-sections.js
deleted file mode 100644
index ab5c5e94d6..0000000000
--- a/app/config/journal/article-sections.js
+++ /dev/null
@@ -1,30 +0,0 @@
-export default [
-  {
-    label: 'Cognitive Psychology',
-    value: 'cognitive-psychology',
-  },
-  {
-    label: 'Social Psychology',
-    value: 'social-psychology',
-  },
-  {
-    label: 'Personality Psychology',
-    value: 'personality-psychology',
-  },
-  {
-    label: 'Developmental Psychology',
-    value: 'developmental-psychology',
-  },
-  {
-    label: 'Clinical Psychology',
-    value: 'clinical-psychology',
-  },
-  {
-    label: 'Organizational Behavior',
-    value: 'organizational-behavior',
-  },
-  {
-    label: 'Methodology and Research Practice',
-    value: 'methodology',
-  },
-]
diff --git a/app/config/journal/declarations.js b/app/config/journal/declarations.js
deleted file mode 100644
index dca117515f..0000000000
--- a/app/config/journal/declarations.js
+++ /dev/null
@@ -1,101 +0,0 @@
-export default {
-  questions: [
-    {
-      id: 'openData',
-      legend: 'Data is open ?',
-      options: [
-        {
-          label: 'Yes',
-          value: 'yes',
-        },
-        {
-          label: 'No/Not Applicable',
-          value: 'no',
-        },
-      ],
-      description:
-        'The journal requires data be openly available, and our full policy is <a href="https://www.collabra.org/about/editorialpolicies/#open-data-open-analytic-methods-code-and-research-materials-transparency" target="_blank">here</a>. If you have exceptions that need to be considered, please click "No" and explain in your cover letter below. Please click N/A if your submission does not feature data.',
-    },
-    {
-      id: 'previouslySubmitted',
-      legend: 'Previously submitted ?',
-      options: [
-        {
-          label: 'Yes',
-          value: 'yes',
-        },
-        {
-          label: 'No',
-          value: 'no',
-        },
-      ],
-      description:
-        'Provide further details in your cover letter below, if necessary.',
-    },
-    {
-      id: 'openPeerReview',
-      legend: 'Open peer review ?',
-      options: [
-        {
-          label: 'Yes',
-          value: 'yes',
-        },
-        {
-          label: 'No',
-          value: 'no',
-        },
-      ],
-      description:
-        'Please read a description of our <a href="https://www.collabra.org/about/editorialpolicies/#open-peer-review" target="_blank">“Open Review”</a> option and select “Yes” if you choose this process.',
-    },
-    {
-      id: 'streamlinedReview',
-      legend: 'Streamlined review ?',
-      options: [
-        {
-          label: 'Yes',
-          value: 'yes',
-        },
-        {
-          label: 'No',
-          value: 'no',
-        },
-      ],
-      description:
-        'Please read a description of our <a href="https://www.collabra.org/about/editorialpolicies/#streamlined-review" target="_blank">“Streamlined Review”</a> option and select “Yes” if you choose this process. If “Yes”, please upload your ported decision letter and reviews as “Supplementary Files” below, clearly labeled.',
-    },
-    {
-      id: 'researchNexus',
-      legend:
-        'Submitted as part of the <a href="https://www.collabra.org/collections/special/" target="_blank">research nexus</a> ?',
-      options: [
-        {
-          label: 'Yes',
-          value: 'yes',
-        },
-        {
-          label: 'No',
-          value: 'no',
-        },
-      ],
-      description:
-        'If yes, mention the name of the Research Nexus in your cover letter below.',
-    },
-    {
-      id: 'preregistered',
-      legend: 'Pre-registered ?',
-      options: [
-        {
-          label: 'Yes',
-          value: 'yes',
-        },
-        {
-          label: 'No',
-          value: 'no',
-        },
-      ],
-      description:
-        'If any or all elements of your study have been pre-registered, click yes and ensure details are in the Acknowledgements section of your manuscript, following these <a href="https://www.collabra.org/about/editorialpolicies/#preregistration-of-studies-and-analysis-plans" target="_blank">guidelines</a>.',
-    },
-  ],
-}
diff --git a/app/config/journal/editors.js b/app/config/journal/editors.js
deleted file mode 100644
index 9c2affbc43..0000000000
--- a/app/config/journal/editors.js
+++ /dev/null
@@ -1,32 +0,0 @@
-export default {
-  handlingEditor: [
-    {
-      name: 'Handling Editor One',
-      user: 5,
-    },
-    {
-      name: 'Handling Editor Two',
-      user: 6,
-    },
-  ],
-  managingEditor: [
-    {
-      name: 'Managing Editor One',
-      user: 1,
-    },
-    {
-      name: 'Managing Editor Two',
-      user: 2,
-    },
-  ],
-  seniorEditor: [
-    {
-      name: 'Senior Editor One',
-      user: 3,
-    },
-    {
-      name: 'Senior Editor Two',
-      user: 4,
-    },
-  ],
-}
diff --git a/app/config/journal/index.js b/app/config/journal/index.js
deleted file mode 100644
index bace9afc1f..0000000000
--- a/app/config/journal/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-export { default as metadata } from './metadata'
-export { default as declarations } from './declarations'
-export { default as decisions } from './decisions'
-export { default as recommendations } from './recommendations'
-export { default as sections } from './sections'
-export { default as articleSections } from './article-sections'
-export { default as articleTypes } from './article-types'
-export { default as editors } from './editors'
-export { default as roles } from './roles'
-export { default as reviewStatus } from './review-status'
-export { default as notes } from './submit-notes'
-export { default as supplementary } from './supplementary'
diff --git a/app/config/journal/metadata.js b/app/config/journal/metadata.js
deleted file mode 100644
index bdb2ef3289..0000000000
--- a/app/config/journal/metadata.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export default {
-  issn: '0000-0001',
-  name: 'SimpleJ',
-}
diff --git a/app/config/journal/review-status.js b/app/config/journal/review-status.js
deleted file mode 100644
index fd8c98ac00..0000000000
--- a/app/config/journal/review-status.js
+++ /dev/null
@@ -1 +0,0 @@
-export default ['invited', 'accepted', 'rejected', 'completed']
diff --git a/config/authsome.js b/config/authsome.js
index 8423ba8918..423148f99f 100644
--- a/config/authsome.js
+++ b/config/authsome.js
@@ -1,8 +1,10 @@
 const { pickBy } = require('lodash')
 
-class SimpleJMode {
+const objType = obj => (obj.constructor && obj.constructor.name) || obj.type
+
+class AuthsomeMode {
   /**
-   * Creates a new instance of SimpleJMode
+   * Creates a new instance of AuthsomeMode
    *
    * @param {string} userId A user's UUID
    * @param {string} operation The operation you're authorizing for
@@ -12,28 +14,11 @@ class SimpleJMode {
    */
   constructor(userId, operation, object, context) {
     this.userId = userId
-    this.operation = SimpleJMode.mapOperation(operation)
+    this.operation = operation
     this.object = object
     this.context = context
   }
 
-  /**
-   * Maps operations from HTTP verbs to semantic verbs
-   *
-   * @param {any} operation
-   * @returns {string}
-   */
-  static mapOperation(operation) {
-    const operationMap = {
-      GET: 'read',
-      POST: 'create',
-      PATCH: 'update',
-      DELETE: 'delete',
-    }
-
-    return operationMap[operation] ? operationMap[operation] : operation
-  }
-
   /**
    * Checks if user is a member of a team of a certain type for a certain object
    *
@@ -42,16 +27,23 @@ class SimpleJMode {
    * @returns {boolean}
    */
   async isTeamMember(role, object) {
-    if (!this.user || !Array.isArray(this.user.teams)) {
+    if (!this.user) {
       return false
     }
 
+    this.user.teams =
+      this.user.teams ||
+      (
+        await this.context.models.User.query()
+          .findById(this.user.id)
+          .eager('teams')
+      ).teams
+
     let membershipCondition
     if (object) {
       // We're asking if a user is a member of a team for a specific object
       membershipCondition = team => {
-        // TODO: This needs to be fixed...
-        const objectId = team.objectId || (team.object && team.object.objectId)
+        const { objectId } = team
         return team.role === role && objectId === object.id
       }
     } else {
@@ -60,11 +52,8 @@ class SimpleJMode {
     }
 
     const memberships = await Promise.all(
-      this.user.teams.map(async teamId => {
-        // TODO: This needs to be fixed...
-        const id = teamId.id ? teamId.id : teamId
-        const team = await this.context.models.Team.find(id)
-        if (!team) return [false]
+      this.user.teams.map(async team => {
+        if (!team) return false
 
         return membershipCondition(team)
       }),
@@ -85,8 +74,7 @@ class SimpleJMode {
   }
 
   /**
-   * Checks if the user is an admin, as represented with the owners
-   * relationship
+   * Checks if the user is an admin
    *
    * @returns {boolean}
    */
@@ -122,21 +110,24 @@ class SimpleJMode {
   }
 
   /**
-   * Checks if user is a senior editor (member of a team of type senior editor) for an object
+   * Checks if user is an editor (any editor) globally
    *
    * @returns {boolean}
    */
-  isManagingEditor(object) {
-    return this.isTeamMember('managingEditor', object)
+  async isGlobalEditor(object) {
+    const seniorEditor = await this.isTeamMember('seniorEditor')
+    const handlingEditor = await this.isTeamMember('handlingEditor')
+
+    return seniorEditor || handlingEditor
   }
 
   /**
-   * Checks if user is a reviewer editor (member of a team of type reviewer editor) for an object
+   * Checks if user is a reviewer (member of a team of type reviewer) for an object
    *
    * @returns {boolean}
    */
-  isAssignedReviewerEditor(object) {
-    return this.isTeamMember('reviewerEditor', object)
+  isAssignedReviewer(object) {
+    return this.isTeamMember('reviewer', object)
   }
 
   /**
@@ -149,15 +140,6 @@ class SimpleJMode {
     return !!this.userId
   }
 
-  /**
-   * Checks if a user can create a collection.
-   *
-   * @returns {boolean}
-   */
-  canCreateCollection() {
-    return this.isAuthenticated()
-  }
-
   /**
    * Checks if a user can read a specific collection
    *
@@ -173,11 +155,6 @@ class SimpleJMode {
 
     const manuscript = this.object
 
-    // TODO: Enable more team types
-    // if (await this.isManagingEditor(manuscript)) {
-    //   return true
-    // }
-
     let permission = await this.checkTeamMembers(
       [
         'isAssignedSeniorEditor',
@@ -258,13 +235,6 @@ class SimpleJMode {
           { id: fragment.collections[0] },
         )
 
-    // permission = permission
-    //   ? true
-    //   : await this.isAssignedManagingEditor(fragment)
-    // Caveat: this means every logged-in user can read every fragment (but needs its UUID)
-    // Ideally we'd check if the fragment (version) belongs to a collection (project)
-    // where the user is a member of a team with the appropriate rights. However there is no
-    // link from a fragment back to a collection at this point. Something to keep in mind!
     return permission
   }
 
@@ -273,41 +243,41 @@ class SimpleJMode {
    *
    * @returns {boolean}
    */
-  // async canListManuscripts() {
-  //   if (!this.isAuthenticated()) {
-  //     return false
-  //   }
-
-  //   this.user = await getUserAndTeams(this.userId, this.context)
-
-  //   return {
-  //     filter: async manuscripts => {
-  //       const filteredManuscripts = await Promise.all(
-  //         manuscripts.map(async manuscript => {
-  //           let condition = await this.checkTeamMembers(
-  //             [
-  //               'isAssignedSeniorEditor',
-  //               'isAssignedHandlingEditor',
-  //               'isManagingEditor',
-  //               'isAssignedReviewerEditor',
-  //             ],
-  //             manuscript,
-  //           )
-  //           // condition = condition
-  //           //   ? true
-  //           //   : await this.canReadatLeastOneFragmentOfCollection(collection, [
-  //           //       'isAssignedReviewerEditor',
-  //           //     ])
-
-  //           condition = condition ? true : await this.isAuthor(manuscript)
-  //           return condition ? manuscript : false
-  //         }),
-  //       )
-
-  //       return filteredManuscripts.filter(manuscript => manuscript)
-  //     },
-  //   }
-  // }
+  async canListManuscripts() {
+    if (!this.isAuthenticated()) {
+      return false
+    }
+
+    this.user = await getUserAndTeams(this.userId, this.context)
+
+    return {
+      filter: async manuscripts => {
+        const filteredManuscripts = await Promise.all(
+          manuscripts.map(async manuscript => {
+            let condition = await this.checkTeamMembers(
+              [
+                'isAssignedSeniorEditor',
+                'isAssignedHandlingEditor',
+                'isManagingEditor',
+                'isAssignedReviewerEditor',
+              ],
+              manuscript,
+            )
+            // condition = condition
+            //   ? true
+            //   : await this.canReadatLeastOneFragmentOfCollection(collection, [
+            //       'isAssignedReviewerEditor',
+            //     ])
+
+            condition = condition ? true : await this.isAuthor(manuscript)
+            return condition ? manuscript : false
+          }),
+        )
+
+        return filteredManuscripts.filter(manuscript => manuscript)
+      },
+    }
+  }
 
   /**
    * Checks if a user can create fragments
@@ -384,7 +354,7 @@ class SimpleJMode {
    * Checks if a user can create a team
    *
    * @returns {boolean}
-   * @memberof SimpleJMode
+   * @memberof AuthsomeMode
    */
   async canCreateTeam() {
     if (!this.isAuthenticated()) {
@@ -472,23 +442,6 @@ class SimpleJMode {
     return permission
   }
 
-  /**
-   * Checks if a user can update manuscript
-   *
-   * @returns {boolean}
-   */
-  // async canUpdateManuscript() {
-  //   this.user = await getUserAndTeams(this.userId, this.context)
-  //   const { current } = this.object
-  //   if (current) {
-  //     return this.checkTeamMembers(
-  //       ['isAuthor', 'isAssignedSeniorEditor', 'isAssignedHandlingEditor'],
-  //       current,
-  //     )
-  //   }
-  //   return false
-  // }
-
   /**
    * Checks if a user can delete Manuscript
    *
@@ -531,31 +484,6 @@ class SimpleJMode {
     )
   }
 
-  async canViewMySubmissionSection() {
-    this.user = await getUserAndTeams(this.userId, this.context)
-    const manuscripts = await Promise.all(
-      this.object.map(async manuscript => this.isAuthor(manuscript)),
-    )
-
-    return manuscripts.some(manuscript => manuscript)
-  }
-
-  async canViewReviewSection() {
-    this.user = await getUserAndTeams(this.userId, this.context)
-
-    const collection = await Promise.all(
-      this.object.map(async manuscript => {
-        const permission = await this.checkTeamMembers(
-          ['isAssignedReviewerEditor'],
-          manuscript,
-        )
-
-        return permission
-      }),
-    )
-    return collection.some(collection => collection)
-  }
-
   async canViewManuscripts() {
     this.user = await getUserAndTeams(this.userId, this.context)
     const manuscripts = await Promise.all(
@@ -571,101 +499,7 @@ class SimpleJMode {
       ),
     )
 
-    return manuscripts.some(collection => collection)
-  }
-
-  async canViewPage() {
-    this.user = await getUserAndTeams(this.userId, this.context)
-    const { path, params } = this.object
-
-    if (path === '/teams') {
-      return !!this.isAdmin()
-    }
-
-    if (path === '/journals/:journal/versions/:version/submit') {
-      return this.checkPageSubmit(params)
-    }
-
-    if (path === '/journals/:journal/versions/:version/reviews/:review') {
-      return this.checkPageReviews(params)
-    }
-
-    if (
-      path === '/journals/:journal/versions/:version/review' ||
-      path === '/journals/:journal/versions/:version/reviewers'
-    ) {
-      return this.checkPageReview(params)
-    }
-
-    if (path === '/journals/:journal/versions/:version/decisions/:decision') {
-      return this.checkPageDecision(params)
-    }
-
-    return true
-  }
-
-  async checkPageSubmit(params) {
-    const collection = this.context.models.Collection.find(params.project)
-    let permission = await this.isAuthor(collection)
-
-    // permission = permission
-    //   ? true
-    //   : await !this.canReadatLeastOneFragmentOfCollection(collection, [
-    //       'isAssignedReviewerEditor',
-    //     ])
-
-    permission = permission
-      ? true
-      : await this.checkTeamMembers(
-          [
-            'isAssignedSeniorEditor',
-            'isAssignedHandlingEditor',
-            'isAssignedReviewerEditor',
-          ],
-          collection,
-        )
-
-    return permission
-  }
-
-  async checkPageDecision(params) {
-    const collection = this.context.models.Collection.find(params.project)
-
-    if (this.isAuthor(collection)) return false
-
-    const permission = await this.checkTeamMembers(
-      ['isAssignedSeniorEditor', 'isAssignedHandlingEditor'],
-      collection,
-    )
-
-    return permission
-  }
-
-  async checkPageReviews(params) {
-    const fragment = this.context.models.Fragment.find(params.version)
-
-    const permission = await this.checkTeamMembers(
-      ['isAssignedReviewerEditor'],
-      fragment,
-    )
-
-    return permission
-  }
-
-  async checkPageReview(params) {
-    const collection = this.context.models.Collection.find(params.project)
-
-    const permission = await this.checkTeamMembers(
-      ['isAssignedSeniorEditor', 'isAssignedHandlingEditor'],
-      collection,
-    )
-
-    return permission
-  }
-
-  async checkTeamMembers(team, object) {
-    const permission = await Promise.all(team.map(t => this[t](object)))
-    return permission.includes(true)
+    return manuscripts.some(m => m)
   }
 }
 
@@ -690,21 +524,11 @@ module.exports = {
     const user = await getUserAndTeams(userId, context)
     if (!user) return false
 
-    // we need to introduce a new Role Managing Editor
-    // currently we take for granted that an admin is the Managing Editor
-    // Temporally we need this if statement to prevent admin from seeing
-    // review and submission section on dashboard (ME permissions)
-    // if (
-    //   operation === 'can view review section' ||
-    //   operation === 'can view my submission section' ||
-    //   operation === 'can view my manuscripts section'
-    // )
-    //   return false
     return user.admin
   },
   create: (userId, operation, object, context) => true,
   update: async (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
+    const mode = new AuthsomeMode(userId, operation, object, context)
 
     if (
       mode.object === 'Manuscript' ||
@@ -734,59 +558,43 @@ module.exports = {
     return false
   },
   delete: (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
+    const mode = new AuthsomeMode(userId, operation, object, context)
 
-    if (object && object.type === 'users') {
+    if (object && objType(object) === 'users') {
       return mode.canDeleteUser()
     }
 
-    if (object === 'Manuscript' || object.type === 'Manuscript') {
+    if (object === 'Manuscript' || objType(object) === 'Manuscript') {
       return mode.isAuthor(object)
     }
 
-    if (object === 'Team' || object.type === 'Team') {
+    if (object === 'Team' || objType(object) === 'Team') {
       return true
       // return mode.canDeleteTeam()
     }
 
     return false
   },
-  'can view my submission section': (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
-    return mode.canViewMySubmissionSection()
-  },
-  'can view my manuscripts section': (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
-    return mode.canViewManuscripts()
-  },
-  'can view review section': (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
-    return mode.canViewReviewSection()
-  },
-  'can delete manuscript': (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
-    return mode.canDeleteManuscript()
-  },
-  'can view page': (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
-    return mode.canViewPage()
-  },
-  'can view only admin': () => false,
   read: async (userId, operation, object, context) => {
-    const mode = new SimpleJMode(userId, operation, object, context)
+    const mode = new AuthsomeMode(userId, operation, object, context)
 
+    // Can a user read (list) Manuscripts or Reviews?
     if (object === 'Manuscript' || object === 'Review') {
       return true
     }
 
-    if (object.type === 'Review') {
+    // Can a user read a specific Review?
+    if (objType(object) === 'Review') {
       return mode.isAllowedToReview(object)
     }
 
-    if (object.type === 'Manuscript') {
+    // Can a user read a specific Manuscript?
+    if (objType(object) === 'Manuscript') {
       return mode.canReadManuscript()
     }
-    if (object.type === 'team' || object === 'Team') {
+
+    // Can a user read
+    if (objType(object) === 'team' || object === 'Team') {
       return mode.canReadTeam()
     }
 
@@ -798,7 +606,7 @@ module.exports = {
       return mode.canListUsers()
     }
 
-    if (object.type === 'user' || object === 'User') {
+    if (objType(object) === 'user' || object === 'User') {
       return mode.canReadUser()
     }
 
diff --git a/config/default.js b/config/default.js
index 5ba4fcd8fd..5f54965366 100644
--- a/config/default.js
+++ b/config/default.js
@@ -44,7 +44,6 @@ module.exports = {
     db: {},
     port: 3000,
     logger,
-    enableExperimentalGraphql: true,
     uploads: 'uploads',
     typeDefs: `
       extend type User {
@@ -134,16 +133,10 @@ module.exports = {
   },
   'pubsweet-client': {
     API_ENDPOINT: '/api',
-    'login-redirect': '/',
+    'login-redirect': '/journal/dashboard',
     'redux-log': false,
     theme: process.env.PUBSWEET_THEME,
   },
-  'password-reset': {
-    url:
-      process.env.PUBSWEET_PASSWORD_RESET_URL ||
-      'http://localhost:3000/password-reset',
-    sender: process.env.PUBSWEET_PASSWORD_RESET_SENDER || 'dev@example.com',
-  },
   'pubsweet-component-xpub-dashboard': {
     acceptUploadFiles: [
       'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
@@ -155,15 +148,6 @@ module.exports = {
       'application/zip',
     ],
   },
-  'pubsweet-component-ink-backend': {
-    inkEndpoint: process.env.INK_ENDPOINT || 'http://167.99.161.30:3000/',
-    email: process.env.INK_USERNAME,
-    password: process.env.INK_PASSWORD,
-    maxRetries: 500,
-    recipes: {
-      'editoria-typescript': '2',
-    },
-  },
   publicKeys: [
     'pubsweet-client',
     'authsome',
@@ -172,6 +156,8 @@ module.exports = {
     'pubsweet-component-xpub-formbuilder',
     'pubsweet',
     'detectionMethodCorrelations',
+    'journal',
   ],
   schema: {},
+  journal: require('./journal'),
 }
diff --git a/config/development.js b/config/development.js
index 98b60078ef..3decc25936 100644
--- a/config/development.js
+++ b/config/development.js
@@ -8,13 +8,11 @@ module.exports = {
     },
     port: process.env.PORT || 3000,
     pool: { min: 0, max: 10, idleTimeoutMillis: 1000 },
-    baseUrl: deferConfig(
-      cfg => `http://localhost:${cfg['pubsweet-server'].port}`,
-    ),
+    baseUrl: `http://localhost:4000`,
     secret: 'secret-string',
   },
   'pubsweet-client': {
-    baseUrl: 'http://localhost:4000/',
+    baseUrl: `http://localhost:4000`,
   },
   mailer: {
     from: 'simplej@example.com',
@@ -26,4 +24,8 @@ module.exports = {
     email: 'admin@admin.com',
     admin: true,
   },
+  'auth-orcid': {
+    clientID: 'APP-91SA3NKY9L7Z2ZQC',
+    clientSecret: '5bfddaea-e02f-429e-aebc-a063edae960e',
+  },
 }
diff --git a/app/config/journal/article-types.js b/config/journal/article-types.js
similarity index 93%
rename from app/config/journal/article-types.js
rename to config/journal/article-types.js
index a5d08e5f98..ccd22cb56c 100644
--- a/app/config/journal/article-types.js
+++ b/config/journal/article-types.js
@@ -1,4 +1,4 @@
-export default [
+module.exports = [
   {
     label: 'Original Research Report',
     value: 'original-research',
diff --git a/app/config/journal/decisions.js b/config/journal/decisions.js
similarity index 96%
rename from app/config/journal/decisions.js
rename to config/journal/decisions.js
index 3b1e485081..bb05921d47 100644
--- a/app/config/journal/decisions.js
+++ b/config/journal/decisions.js
@@ -1,4 +1,4 @@
-export default {
+module.exports = {
   accepted: {
     color: 'green',
     label: 'Accept',
diff --git a/config/journal/index.js b/config/journal/index.js
new file mode 100644
index 0000000000..8b7b245e19
--- /dev/null
+++ b/config/journal/index.js
@@ -0,0 +1,11 @@
+module.exports = {
+  metadata: require('./metadata'),
+  decisions: require('./decisions'),
+  recommendations: require('./recommendations'),
+  sections: require('./sections'),
+  articleTypes: require('./article-types'),
+  roles: require('./roles'),
+  reviewStatus: require('./review-status'),
+  notes: require('./submit-notes'),
+  supplementary: require('./supplementary'),
+}
diff --git a/config/journal/metadata.js b/config/journal/metadata.js
new file mode 100644
index 0000000000..47074571b8
--- /dev/null
+++ b/config/journal/metadata.js
@@ -0,0 +1,4 @@
+module.exports = {
+  issn: '0000-0001',
+  name: 'Aperture',
+}
diff --git a/app/config/journal/recommendations.js b/config/journal/recommendations.js
similarity index 91%
rename from app/config/journal/recommendations.js
rename to config/journal/recommendations.js
index 642d16fafd..b378e93713 100644
--- a/app/config/journal/recommendations.js
+++ b/config/journal/recommendations.js
@@ -1,4 +1,4 @@
-export default [
+module.exports = [
   {
     color: 'green',
     label: 'Accept',
diff --git a/config/journal/review-status.js b/config/journal/review-status.js
new file mode 100644
index 0000000000..3a728ff523
--- /dev/null
+++ b/config/journal/review-status.js
@@ -0,0 +1 @@
+module.exports = ['invited', 'accepted', 'rejected', 'completed']
diff --git a/app/config/journal/roles.js b/config/journal/roles.js
similarity index 87%
rename from app/config/journal/roles.js
rename to config/journal/roles.js
index 0f9334d4c6..95129e0a1e 100644
--- a/app/config/journal/roles.js
+++ b/config/journal/roles.js
@@ -1,4 +1,4 @@
-export default {
+module.exports = {
   author: 'Author',
   handlingEditor: 'Handling Editor',
   managingEditor: 'Managing Editor',
diff --git a/app/config/journal/sections.js b/config/journal/sections.js
similarity index 76%
rename from app/config/journal/sections.js
rename to config/journal/sections.js
index 72bbd760b7..063ea160fa 100644
--- a/app/config/journal/sections.js
+++ b/config/journal/sections.js
@@ -1,4 +1,4 @@
-export default [
+module.exports = [
   {
     id: 'submissions',
     label: 'My Submissions',
diff --git a/app/config/journal/submit-notes.js b/config/journal/submit-notes.js
similarity index 97%
rename from app/config/journal/submit-notes.js
rename to config/journal/submit-notes.js
index 1e811e33f2..d5e7bd08b1 100644
--- a/app/config/journal/submit-notes.js
+++ b/config/journal/submit-notes.js
@@ -1,4 +1,4 @@
-export default {
+module.exports = {
   fundingAcknowledgement: {
     placeholder: 'Enter an acknowledgment…',
     title: 'Funding body acknowledgement (required)',
diff --git a/app/config/journal/supplementary.js b/config/journal/supplementary.js
similarity index 84%
rename from app/config/journal/supplementary.js
rename to config/journal/supplementary.js
index 6904c399a8..2b0aff3f7a 100644
--- a/app/config/journal/supplementary.js
+++ b/config/journal/supplementary.js
@@ -1,4 +1,4 @@
-export default {
+module.exports = {
   description: `
     <pre>All neccessary supplementary files for your research objects
     </pre>
-- 
GitLab