Commit e9c43b34 authored by Giannis Kopanas's avatar Giannis Kopanas

Merge branch 'data-modeling-graphql' into 'master'

graphql mocking server

See merge request !245
parents 893a1f8c f9f87f34
Pipeline #10952 failed with stages
in 2 minutes and 34 seconds
{
"projects": {
"xpub": {
"schemaPath": "schema.graphql",
"extensions": {
"endpoints": {
"dev": "http://localhost:3000/graphql"
}
}
}
}
}
\ No newline at end of file
......@@ -31,6 +31,7 @@ COPY config config
COPY scripts scripts
COPY static static
COPY test test
COPY server server
COPY webpack webpack
ENV NODE_ENV ${NODE_ENV}
......
import React from 'react'
import styled from 'styled-components'
import { compose, withState, withHandlers, lifecycle } from 'recompose'
import { connect } from 'react-redux'
import withAuthsome from 'pubsweet-client/src/helpers/withAuthsome'
import { withRouter, matchPath } from 'react-router-dom'
// import PropTypes from 'prop-types'
import { compose, withState, withProps } from 'recompose'
import { graphql, withApollo } from 'react-apollo'
import { createContext } from 'xpub-with-context'
import { withRouter, matchPath, Router } from 'react-router-dom'
import { Action, AppBar } from '@pubsweet/ui'
import { withJournal } from 'xpub-journal'
import actions from 'pubsweet-client/src/actions'
import queries from '../graphql/'
const getParams = routerPath => {
const path = '/projects/:project/versions/:version'
const path = '/journals/:journal/versions/:version'
return matchPath(routerPath, path).params
}
......@@ -20,8 +19,8 @@ const MainPage = styled.div`
`
const Root = styled.div`
${({ disableLinks }) =>
disableLinks &&
${({ converting }) =>
converting &&
`
button,
a {
......@@ -30,15 +29,18 @@ const Root = styled.div`
`};
`
const localStorage = window.localStorage || undefined
const App = ({
authorized,
children,
client,
currentUser,
journal,
logoutUser,
history,
match,
disableLinks,
conversion,
}) => {
const { pathname } = history.location
const showLinks = pathname.match(/submit|manuscript/g)
......@@ -47,7 +49,7 @@ const App = ({
if (showLinks) {
const params = getParams(pathname)
const baseLink = `/projects/${params.project}/versions/${params.version}`
const baseLink = `/journals/${params.journal}/versions/${params.version}`
const submitLink = `${baseLink}/submit`
const manuscriptLink = `${baseLink}/manuscript`
......@@ -71,7 +73,7 @@ const App = ({
: null
}
if (authorized) {
if (currentUser && currentUser.admin) {
links.push(
<Action
active={window.location.pathname === '/teams' ? 'active' : null}
......@@ -92,42 +94,35 @@ const App = ({
}
return (
<Root disableLinks={disableLinks}>
<Root converting={conversion.converting}>
<AppBar
brand={journal.metadata.name}
navLinkComponents={links}
onLogoutClick={logoutUser}
onLogoutClick={() => logoutUser(client)}
user={currentUser}
/>
<MainPage>{children}</MainPage>
<Router history={history}>
<MainPage>{children}</MainPage>
</Router>
</Root>
)
}
export default compose(
connect(
state => ({
currentUser: state.currentUser.user,
disableLinks: state.conversion.converting,
}),
{ logoutUser: actions.logoutUser },
),
withAuthsome(),
withState('authorized', 'authorizeCheck', false),
withHandlers({
authorizeCheckfn: ({ authorizeCheck, currentUser, authsome }) => () =>
authsome
.can(currentUser && currentUser.id, 'can view teams menu', {})
.then(result => authorizeCheck(() => result)),
graphql(queries.currentUser, {
props: ({ data }) => data,
// eslint-disable-next-line
skip: () => (localStorage.getItem('token') ? false : true),
}),
withJournal,
withRouter,
lifecycle({
componentDidUpdate(prevProps) {
if (prevProps.currentUser !== this.props.currentUser) {
this.props.authorizeCheckfn()
}
withApollo,
withProps(props => ({
logoutUser: client => {
localStorage.removeItem('token')
client.resetStore()
},
}),
})),
withRouter,
withState('conversion', 'setConversionState', { converting: false }),
createContext(),
)(App)
export default {
accept: {
accepted: {
color: 'green',
label: 'Accept',
message: 'The submission has been accepted for publication',
......@@ -15,7 +15,7 @@ export default {
message:
'The submission will be accepted for publication after minor changes',
},
reject: {
rejected: {
color: 'red',
label: 'Reject',
message: 'The submission is not acceptable for publication',
......
......@@ -2,7 +2,7 @@ export default [
{
color: 'green',
label: 'Accept',
value: 'accept',
value: 'accepted',
},
{
color: 'orange',
......@@ -12,6 +12,6 @@ export default [
{
color: 'red',
label: 'Reject',
value: 'reject',
value: 'rejected',
},
]
import gql from 'graphql-tag'
export default {
currentUser: gql`
{
currentUser {
id
username
admin
}
}
`,
}
import React from 'react'
import { withProps } from 'recompose'
import { Route, Switch } from 'react-router-dom'
import { AuthenticatedComponent } from 'pubsweet-client'
import { Route, Switch, Redirect } from 'react-router-dom'
// import AuthorizeWithGraphQL from 'pubsweet-client/src/helpers/AuthorizeWithGraphQL'
import Login from 'pubsweet-component-login/LoginContainer'
import Signup from 'pubsweet-component-signup/SignupContainer'
......@@ -21,19 +21,25 @@ import TeamPage from 'pubsweet-component-xpub-teams-manager/src/components/Teams
import DecisionPage from 'pubsweet-component-xpub-review/src/components/DecisionPage'
import UsersManager from 'pubsweet-component-users-manager/src/UsersManagerContainer'
import FormBuilderPage from 'pubsweet-component-xpub-formbuilder/src/components/FormBuilderPage'
// import SimpleFormBuilderPage from 'pubsweet-component-xpub-simple-formbuilder/src/components/SimpleFormBuilderPage'
import App from './components/App'
const LoginPage = withProps({ passwordReset: false })(Login)
const createReturnUrl = ({ pathname, search = '' }) => pathname + search
const loginUrl = location => `/login?next=${createReturnUrl(location)}`
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props => (
<AuthenticatedComponent>
render={props =>
localStorage.getItem('token') ? (
<Component {...props} />
</AuthenticatedComponent>
)}
) : (
<Redirect to={loginUrl(props.location)} />
)
}
/>
)
......@@ -46,7 +52,7 @@ const Routes = () => (
<PrivateRoute
component={SubmitPage}
exact
path="/projects/:project/versions/:version/submit"
path="/journals/:journal/versions/:version/submit"
/>
<PrivateRoute component={TeamPage} exact path="/teams" />
<PrivateRoute
......@@ -54,40 +60,45 @@ const Routes = () => (
exact
path="/admin/form-builder"
/>
{/* <PrivateRoute
component={SimpleFormBuilderPage}
exact
path="/admin/simple-form-builder"
/> */}
<PrivateRoute
component={ManuscriptPage}
exact
path="/projects/:project/versions/:version/manuscript"
path="/journals/:journal/versions/:version/manuscript"
/>
<PrivateRoute
component={ReviewersPage}
exact
path="/projects/:project/versions/:version/reviewers"
path="/journals/:journal/versions/:version/reviewers"
/>
<PrivateRoute
component={ReviewPage}
exact
path="/projects/:project/versions/:version/reviews/:review"
path="/journals/:journal/versions/:version/reviews/:review"
/>
<PrivateRoute
component={DecisionPage}
exact
path="/projects/:project/versions/:version/decisions/:decision"
path="/journals/:journal/versions/:version/decisions/:decision"
/>
{/* <PrivateRoute
component={FindReviewersPage}
exact
path="/projects/:project/versions/:version/find-reviewers"
path="/journals/:journal/versions/:version/find-reviewers"
/>
<PrivateRoute
component={FindReviewersAuthorPage}
exact
path="/projects/:project/versions/:version/find-reviewers/author/:id"
path="/journals/:journal/versions/:version/find-reviewers/author/:id"
/>
<PrivateRoute
component={FindReviewersPaperPage}
exact
path="/projects/:project/versions/:version/find-reviewers/paper/:id"
path="/journals/:journal/versions/:version/find-reviewers/paper/:id"
/> */}
<Route component={Signup} exact path="/signup" />
......
This diff is collapsed.
This diff is collapsed.
......@@ -8,5 +8,10 @@
"pubsweet-component-login",
"pubsweet-component-signup",
"pubsweet-component-xpub-teams-manager",
"pubsweet-component-xpub-formbuilder"
"pubsweet-component-xpub-formbuilder",
"server/journal/src/",
"server/manuscript/src/",
"server/review/src/",
"server/file/src/",
"server/formbuilder/src/"
]
......@@ -4,7 +4,7 @@ const logger = require('winston')
module.exports = {
authsome: {
mode: path.resolve(__dirname, 'authsome.js'),
mode: path.resolve(__dirname, 'authsomeGraphql.js'),
teams: {
seniorEditor: {
name: 'Senior Editors',
......@@ -22,6 +22,10 @@ module.exports = {
name: 'Reviewer',
permissions: '',
},
author: {
name: 'Authors',
permissions: '',
},
},
},
validations: path.resolve(__dirname, 'validations.js'),
......@@ -40,6 +44,7 @@ module.exports = {
db: {},
port: 3000,
logger,
enableExperimentalGraphql: true,
uploads: 'uploads',
typeDefs: `
extend type User {
......@@ -150,8 +155,7 @@ module.exports = {
],
},
'pubsweet-component-ink-backend': {
inkEndpoint:
process.env.INK_ENDPOINT || 'http://inkdemo-api.coko.foundation/',
inkEndpoint: process.env.INK_ENDPOINT || 'http://167.99.161.30:3000/',
email: process.env.INK_USERNAME,
password: process.env.INK_PASSWORD,
maxRetries: 500,
......@@ -165,5 +169,8 @@ module.exports = {
'validations',
'pubsweet-component-xpub-dashboard',
'pubsweet-component-xpub-formbuilder',
'pubsweet',
'detectionMethodCorrelations',
],
schema: {},
}
......@@ -30,5 +30,37 @@
}]
}
}
},
"Notes": {
"id": {
"component": "TextField"
},
"title": {
"component": "TextField"
},
"name": {
"component": "TextField"
},
"order": {
"component": "TextField"
},
"validate": {
"component": "Menu",
"props": {
"multi": true,
"options": [{
"value": "required",
"label": "Required"
},
{
"value": "minChars",
"label": "minimum Characters"
},
{
"value": "maxChars",
"label": "maximum Characters"
}]
}
}
}
}
\ No newline at end of file
const { deferConfig } = require('config/defer')
const winston = require('winston')
const logger = require('winston')
const components = require('./components.json')
module.exports = {
pubsweet: {
components,
},
'pubsweet-server': {
db: {
database: 'test',
},
ignoreTerminatedConnectionError: true,
logger: new winston.Logger({
level: 'warn',
transports: [new winston.transports.Console()],
}),
logger,
uploads: 'uploads',
enableExperimentalGraphql: true,
port: 4000,
secret: 'secret-string',
baseUrl: deferConfig(
......
......@@ -67,5 +67,6 @@ module.exports = {
},
team: {
group: Joi.string(),
status: Joi.array().items(Joi.object()),
},
}
{
"name": "xpub-collabra",
"version": "0.0.1",
"version": "1.0.0",
"private": true,
"workspaces": [],
"description": "xpub configured for Collabra",
......@@ -14,47 +14,49 @@
"url": "https://gitlab.coko.foundation/xpub/xpub"
},
"dependencies": {
"@pubsweet/coko-theme": "4.1.0",
"@pubsweet/ui": "8.6.1",
"@pubsweet/db-manager": "^1.1.0",
"@pubsweet/base-model": "^1.1.0",
"@pubsweet/coko-theme": "5.0.7",
"@pubsweet/ui": "9.1.3",
"apollo-link-schema": "^1.1.1",
"apollo-link-context": "^1.0.9",
"babel-core": "^6.26.0",
"config": "^1.26.2",
"faker": "^4.1.0",
"font-awesome": "^4.7.0",
"fs-extra": "^4.0.2",
"graphql": "^14.0.2",
"graphql-tools": "^4.0.0",
"history": "^4.7.2",
"joi": "^10.0.6",
"loadable-components": "^0.3.0",
"moment": "^2.18.1",
"prop-types": "^15.5.10",
"pubsweet": "^2.2.4",
"pubsweet-client": "4.2.1",
"styled-components": "4.1.1",
"pubsweet": "^3.0.5",
"pubsweet-client": "8.0.4",
"pubsweet-component-ink-backend": "^0.1.1",
"pubsweet-component-ink-frontend": "^1.0.2",
"pubsweet-component-login": "^1.1.15",
"pubsweet-component-signup": "^1.0.29",
"pubsweet-component-teams-manager": "^1.1.14",
"pubsweet-component-login": "^1.2.8",
"pubsweet-component-signup": "^1.0.41",
"pubsweet-component-users-manager": "^2.0.1",
"pubsweet-component-xpub-dashboard": "^3.0.11",
"pubsweet-component-xpub-dashboard": "^4.0.7",
"pubsweet-component-xpub-find-reviewers": "^0.0.6",
"pubsweet-component-xpub-manuscript": "^0.5.1",
"pubsweet-component-xpub-review": "^3.1.10",
"pubsweet-component-xpub-review-backend": "^0.2.4",
"pubsweet-component-xpub-submit": "^4.1.1",
"pubsweet-component-xpub-formbuilder": "^0.1.1",
"pubsweet-server": "^7.2.0",
"pubsweet-component-xpub-teams-manager": "^0.1.1",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"pubsweet-component-xpub-formbuilder": "^1.0.7",
"pubsweet-component-xpub-manuscript": "^0.6.8",
"pubsweet-component-xpub-review": "^4.0.7",
"pubsweet-component-xpub-review-backend": "^0.2.3",
"pubsweet-component-xpub-submit": "^5.0.7",
"pubsweet-component-xpub-teams-manager": "^1.0.7",
"pubsweet-server": "10.1.0",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2",
"recompose": "^0.26.0",
"redux": "^3.6.0",
"redux-form": "^7.0.3",
"redux-logger": "^3.0.1",
"supertest": "^3.0.0",
"winston": "^2.4.0",
"xpub-journal": "^0.0.6",
"xpub-selectors": "^0.1.0",
"xpub-selectors": "^0.2.0",
"xpub-with-context": "^0.1.4",
"xpub-theme": "^0.0.7"
},
"devDependencies": {
......
{
ignore: ["*"]
}
const BaseModel = require('@pubsweet/base-model')
const logger = require('@pubsweet/logger')
class File extends BaseModel {
static get tableName() {
return 'files'
}
constructor(properties) {
super(properties)
this.type = 'file'
}
static get schema() {
return {
properties: {
label: { type: ['string', 'null'] },
url: { type: ['string', 'null'] },
mimeType: { type: ['string', 'null'] },
fileType: { type: ['string', 'null'] },
filename: { type: ['string', 'null'] },
size: { type: ['integer', 'null'] },
object: { type: ['string', 'null'] },
objectId: { type: 'string', format: 'uuid' },
},
}
}
static async findByObject({ object, object_id }) {
logger.debug('Finding Files by Object')
const results = await this.query()
.where('object', object)
.andWhere('object_id', object_id)
return results
}
// async $beforeDelete() {
// await Team.deleteAssociated(this.data.type, this.id)
// }
}
File.type = 'file'
module.exports = File
const resolvers = require('./resolvers')
const typeDefs = require('./typeDefs')
const model = require('./file')
module.exports = {
model,
modelName: 'File',
resolvers,
typeDefs,
}
CREATE TABLE files (
id UUID PRIMARY KEY,
created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp,
updated TIMESTAMP WITH TIME ZONE,
object TEXT,
object_id UUID,
label TEXT,
file_type TEXT,
filename TEXT,
url TEXT,
mime_type TEXT,
size INTEGER,
type TEXT NOT NULL
);
\ No newline at end of file
const File = require('./file')
const resolvers = {
Query: {},
Mutation: {
async createFile(_, { id, file }, ctx) {
const data = await new File(file).save()
return data
},
},
}
module.exports = resolvers
const typeDefs = `
extend type Mutation {
createFile(file: Upload!): File!
}
type File implements Object {
id: ID!
created: DateTime!
updated: DateTime
object: String
objectId: ID!
label: String
fileType: String
filename: String
url: String
mimeType: String
size: Int
}
`
module.exports = typeDefs
const resolvers = require('./resolvers')
const typeDefs = require('./typeDefs')
module.exports = {
resolvers,
typeDefs,
}
CREATE TABLE manuscripts (
id UUID PRIMARY KEY,
created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp,
updated TIMESTAMP WITH TIME ZONE,
parent_id UUID,
status TEXT,
decision TEXT,
authors JSONB,
suggestions JSONB,
meta JSONB,
type TEXT NOT NULL
);
\ No newline at end of file
const config = require('config')
const fs = require('fs')
const { readFiles, mkdirp } = require('./util')
const form = require('../../../app/storage/forms/submit.json')
const mergeFiles = path =>
readFiles(path).then(files => {
const forms = []
files.forEach((item, index) => {
const content = JSON.parse(item.content)
if (!content.name) return
forms.push(content)
})
return { forms }
})
const resolvers = {
Mutation: {
async deleteForms(_, { formId }, ctx) {
// DONE
try {
const folderPath = `${config.get(
'pubsweet-component-xpub-formbuilder.path',
)}/`
const path = `${folderPath}${formId}.json`
if (fs.existsSync(path)) {
fs.unlinkSync(path)
}
const forms = await mergeFiles(folderPath)
return forms
} catch (err) {
throw new Error(err)
}
},
async deleteFormElement(_, { formId, elementId }, ctx) {
// DONE
try {
const folderPath = `${config.get(
'pubsweet-component-xpub-formbuilder.path',
)}/`
const path = `${folderPath}/${formId}.json`
const forms = JSON.parse(fs.readFileSync(path, 'utf8'))
if (forms.children) {
const children = forms.children.filter(el => el.id !== elementId)
forms.children = children
fs.writeFileSync(path, JSON.stringify(forms))