diff --git a/Automation/src/test/java/Constants.java b/Automation/src/test/java/Constants.java index efd77bf67facffb38475024187eb57a86cde2e59..eb6c8404b0ab402799ef0c44e580b4c051178a53 100644 --- a/Automation/src/test/java/Constants.java +++ b/Automation/src/test/java/Constants.java @@ -1,11 +1,29 @@ +import org.apache.commons.lang3.RandomStringUtils; + public class Constants { - public static final String URL = "http://ec2co-ecsel-m3gy9h288kzs-2054883442.eu-west-1.elb.amazonaws.com/"; + public static final String URL = "http://qa.review.hindawi.com"; public static final String email = "adrian.onofrei+"; - public static final String firstname = "Test FN"; - public static final String lastname = "test LN"; + public static final String firstname = "Test Author"; + public static final String lastname = "Test Author"; public static final String affiliation = "TS affiliation"; - public static final String password = "Testing123"; + public static final String password = "password"; public static final String adminEmail = "admin"; public static final String adminPass = "password"; + public static final String randomStr = RandomStringUtils.randomAlphabetic(4); + public static final String firstnameHE = "Test HE"; + public static final String lastnameHE = "Test HE"; + public static final String passwordHE = "Testing123"; + public static final String emailHE = "adrian.onofrei+HE"; + public static final String affiliationHE = "TS HE affiliation"; + public static final String manusName = RandomStringUtils.randomAlphabetic(16); + public static final String manusAbstract = RandomStringUtils.randomAlphabetic(16); + public static final String fileManuscript = "/Users/adionofrei/Documents/Manuscript.pdf"; + public static final String fileSupplementary = "/Users/adionofrei/Documents/Manuscript.pdf"; + public static final String fileCoverLetter = "/Users/adionofrei/Documents/Manuscript.pdf"; + + + public static String uidAuth = null; + public static String uidHE = null; + } diff --git a/Automation/src/test/java/CreateAccounts.java b/Automation/src/test/java/CreateAccounts.java new file mode 100644 index 0000000000000000000000000000000000000000..a8b5fca1fdd64bc0008eb314627e10ee0c6dcb76 --- /dev/null +++ b/Automation/src/test/java/CreateAccounts.java @@ -0,0 +1,179 @@ +import io.restassured.path.json.JsonPath; +import org.junit.*; +import org.openqa.selenium.*; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import static org.junit.Assert.*; +import io.restassured.RestAssured; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import org.json.simple.JSONObject; +import java.net.URL; + + +public class CreateAccounts { + + private static WebDriver driver = null; + private static WebDriverWait wait = null; + public String URL = Constants.URL; + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + //driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.firefox()); + driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.chrome()); + //driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); + wait = new WebDriverWait(driver, 10); + String window = driver.getWindowHandle(); + ((JavascriptExecutor) driver).executeScript("alert('Test')"); + driver.switchTo().alert().accept(); + driver.switchTo().window(window); + Utils.disableWarning(); + } + + + @After + public void tearDown() { + driver.quit(); + } + + @Test + public void createNewAuthor() throws Exception { + + Utils.createAuthor(driver,wait, URL, Constants.randomStr, Constants.firstname, Constants.lastname, Constants.affiliation, Constants.email + Constants.randomStr + "@thinslices.com",Constants.password); + + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']"))); + } catch (NoSuchElementException e) { + System.out.println(e.toString()); + } + + WebElement element = driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[1]/div[1]/div[2]/div/span[2]")); + String username = element.getText(); + + assertEquals(Constants.firstname+Constants.randomStr, username); + + RestAssured.baseURI = URL; + + //Get user token after login with new account + + RequestSpecification request = RestAssured.given().header("Content-Type", "application/json"); + + JSONObject requestParams = new JSONObject(); + requestParams.put("username", Constants.email + Constants.randomStr + "@thinslices.com"); + requestParams.put("password", Constants.password); + request.body(requestParams.toJSONString()); + Response response = request.post("api/users/authenticate"); + + JsonPath jsonPathEvaluator = response.body().jsonPath(); + String token = jsonPathEvaluator.get("token"); + + //Get user ID and confirmationToken + + RequestSpecification requestUid = RestAssured.given().header("Authorization", "Bearer " + token); + Response responseUid = requestUid.get("api/users/authenticate"); + JsonPath jsonPathEvaluatorUid = responseUid.body().jsonPath(); + + String confirmationToken = jsonPathEvaluatorUid.get("confirmationToken"); + + Constants.uidAuth = jsonPathEvaluatorUid.get("id"); + + //Activate user + + driver.get(URL + "confirm-signup?userId=" + Constants.uidAuth + "&confirmationToken=" + confirmationToken); + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'" + "Go to Dashboard" + "')]"))); + } catch (NoSuchElementException e) { + System.out.println(e.toString()); + } + + assertEquals("Your account has been successfully confirmed. Welcome to Hindawi!", driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[2]/div/div")).getText()); + } + + @Test + public void createNewHE() throws Exception { + + Utils.createAuthor(driver,wait, URL, Constants.randomStr, Constants.firstnameHE, Constants.lastnameHE, Constants.affiliationHE, Constants.emailHE + Constants.randomStr + "@thinslices.com",Constants.passwordHE); + + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']"))); + } catch (NoSuchElementException e) { + System.out.println(e.toString()); + } + + WebElement element = driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[1]/div[1]/div[2]/div/span[2]")); + String username = element.getText(); + + assertEquals(Constants.firstnameHE + Constants.randomStr, username); + + RestAssured.baseURI = URL; + + //Get user token after login with new account + + RequestSpecification request = RestAssured.given().header("Content-Type", "application/json"); + + JSONObject requestParams = new JSONObject(); + requestParams.put("username", Constants.emailHE + Constants.randomStr + "@thinslices.com"); + requestParams.put("password", Constants.passwordHE); + request.body(requestParams.toJSONString()); + Response response = request.post("api/users/authenticate"); + + JsonPath jsonPathEvaluator = response.body().jsonPath(); + String token = jsonPathEvaluator.get("token"); + + //Get user ID and confirmationToken + + RequestSpecification requestUid = RestAssured.given().header("Authorization", "Bearer " + token); + Response responseUid = requestUid.get("api/users/authenticate"); + JsonPath jsonPathEvaluatorUid = responseUid.body().jsonPath(); + + String confirmationToken = jsonPathEvaluatorUid.get("confirmationToken"); + Constants.uidHE = jsonPathEvaluatorUid.get("id"); + + //Activate user + + driver.get(URL + "confirm-signup?userId=" + Constants.uidHE + "&confirmationToken=" + confirmationToken); + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'" + "Go to Dashboard" + "')]"))); + } catch (NoSuchElementException e) { + System.out.println(e.toString()); + } + + assertEquals("Your account has been successfully confirmed. Welcome to Hindawi!", driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[2]/div/div")).getText()); + + driver.get(URL+"login?next=/"); + Utils.validLogin( driver, wait, URL, Constants.adminEmail, Constants.adminPass); + driver.get(URL + "admin/users/edit/" + Constants.uidHE); + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'" + "Save user" + "')]"))); + } catch (NoSuchElementException e) { + System.out.println(e.toString()); + } + + driver.findElement(By.cssSelector("input[name=handlingEditor] + span")).click(); + driver.findElement(By.cssSelector("button[type=submit]")).click(); + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='button-add-user']"))); + } catch (NoSuchElementException e) { + System.out.println(e.toString()); + } + + assertEquals(URL + "admin/users", driver.getCurrentUrl() ); + assertEquals(" Add User", driver.findElement(By.cssSelector("button[data-test='button-add-user']")).getText()); + } +} diff --git a/Automation/src/test/java/CreateAuthor.java b/Automation/src/test/java/CreateAuthor.java deleted file mode 100644 index 065b1e9293836ec8c850debbbb240876f80fe07f..0000000000000000000000000000000000000000 --- a/Automation/src/test/java/CreateAuthor.java +++ /dev/null @@ -1,104 +0,0 @@ -import io.restassured.path.json.JsonPath; -import org.apache.commons.lang3.RandomStringUtils; -import org.junit.*; -import org.openqa.selenium.*; -import org.openqa.selenium.remote.DesiredCapabilities; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.WebDriverWait; -import static org.junit.Assert.*; -import io.restassured.RestAssured; -import io.restassured.response.Response; -import io.restassured.specification.RequestSpecification; -import org.json.simple.JSONObject; -import java.net.URL; - - -public class CreateAuthor { - - private static WebDriver driver = null; - private static WebDriverWait wait = null; - public String URL = Constants.URL; - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - //driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.firefox()); - driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.chrome()); - //driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); - wait = new WebDriverWait(driver, 10); - String window = driver.getWindowHandle(); - ((JavascriptExecutor) driver).executeScript("alert('Test')"); - driver.switchTo().alert().accept(); - driver.switchTo().window(window); - Utils.disableWarning(); - } - - - @After - public void tearDown() { - driver.quit(); - } - - @Test - public void createNewAuthor() throws Exception { - - String s = RandomStringUtils.randomAlphabetic(8); - Utils.createAuthor(driver,wait, URL, s, Constants.firstname, Constants.lastname, Constants.affiliation, Constants.email+s+"@thinslices.com",Constants.password); - - - try { - wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']"))); - } catch (NoSuchElementException e) { - System.out.println(e.toString()); - } - - WebElement element = driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[1]/div[1]/div[2]/div/span[2]")); - String username = element.getText(); - - assertEquals(Constants.firstname+s, username); - - RestAssured.baseURI = URL; - - //Get user token after login with new account - - RequestSpecification request = RestAssured.given().header("Content-Type", "application/json"); - - JSONObject requestParams = new JSONObject(); - requestParams.put("username", Constants.email+s+"@thinslices.com"); - requestParams.put("password", Constants.password); - request.body(requestParams.toJSONString()); - Response response = request.post("api/users/authenticate"); - - JsonPath jsonPathEvaluator = response.body().jsonPath(); - String token = jsonPathEvaluator.get("token"); - - //Get user ID and confimationToken - - RequestSpecification requestUid = RestAssured.given().header("Authorization", "Bearer "+token); - Response responseUid = requestUid.get("api/users/authenticate"); - JsonPath jsonPathEvaluatorUid = responseUid.body().jsonPath(); - - String confirmationToken = jsonPathEvaluatorUid.get("confirmationToken"); - String uid = jsonPathEvaluatorUid.get("id"); - - //Activate user - - driver.get(URL+"confirm-signup?userId="+uid+"&confirmationToken="+confirmationToken); - - try { - wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'"+"Go to Dashboard"+"')]"))); - } catch (NoSuchElementException e) { - System.out.println(e.toString()); - } - - assertEquals("Your account has been successfully confirmed. Welcome to Hindawi!", driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[2]/div/div")).getText()); - } -} diff --git a/Automation/src/test/java/ManuscriptFlow.java b/Automation/src/test/java/ManuscriptFlow.java new file mode 100644 index 0000000000000000000000000000000000000000..db5c49a8195c8c125f5c3e817dabf4eef76a07bb --- /dev/null +++ b/Automation/src/test/java/ManuscriptFlow.java @@ -0,0 +1,155 @@ +import io.restassured.RestAssured; +import io.restassured.path.json.JsonPath; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import org.json.simple.JSONObject; +import org.junit.*; +import org.openqa.selenium.*; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Select; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.net.URL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class ManuscriptFlow { + private static WebDriver driver = null; + private static WebDriverWait wait = null; + public String URL = Constants.URL; + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + //driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.firefox()); + driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.chrome()); + //driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); + wait = new WebDriverWait(driver, 10); + String window = driver.getWindowHandle(); + ((JavascriptExecutor) driver).executeScript("alert('Test')"); + driver.switchTo().alert().accept(); + driver.switchTo().window(window); + } + + @After + public void tearDown() throws Exception { + //driver.quit(); + } + + @Test + public void manuscriptFlow() throws Exception { + /* Add constants.random after testing this function separably */ + Utils.validLogin( driver, wait, URL, Constants.email + /*Constants.randomStr*/ "auth1" + "@thinslices.com", Constants.password); + + WebElement validLogin = null; + + try { + validLogin = wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']"))); + } catch (NoSuchElementException e) { + + } + + assertNotNull(validLogin); + + driver.findElement(By.cssSelector("button[data-test='new-manuscript']")).click(); + + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='submission-next']"))); + } catch (NoSuchElementException e) { + + } + + assertNotNull(driver.findElement(By.cssSelector("button[data-test='submission-next']"))); + + // First step submission flow + driver.findElement(By.cssSelector("[data-test-id='agree-checkbox']")).click(); + driver.findElement(By.cssSelector("button[data-test='submission-next']")).click(); + + // Second step submission flow + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".wizard-step >[data-test-id='row']:nth-of-type(2) span"))); + } catch (NoSuchElementException e) { + + } + + assertEquals("Please provide the details of all the authors of this manuscript, in the order that they appear on the manuscript. Your details have been prefilled as the submitting author.",driver.findElement(By.cssSelector(".wizard-step >[data-test-id='row']:nth-of-type(2) span")).getText()); + assertEquals("MANUSCRIPT TITLE\n*", driver.findElement(By.cssSelector("[data-test-id='submission-title']")).getText()); + + driver.findElement(By.cssSelector("input[name='metadata.title']")).sendKeys(Constants.manusName); + driver.findElement(By.cssSelector("[data-test-id='submission-type']")).click(); + try { + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("[data-test-id='submission-type'] div[role=\"option\"]"))); + } catch (NoSuchElementException e) { + + } + driver.findElement(By.cssSelector("[data-test-id='submission-type'] div[role=\"option\"]:nth-child(1)")).click(); + driver.findElement(By.cssSelector("[data-test-id='submission-abstract'] textarea")).sendKeys(Constants.manusAbstract); + WebElement element = driver.findElement(By.cssSelector("[name='conflicts.hasConflicts'][value='no']")); + + Utils.scrollToElement(driver, element); + element.click(); + + driver.findElement(By.cssSelector("[name='conflicts.hasDataAvailability'][value='yes']")).click(); + WebElement element1 = driver.findElement(By.cssSelector("[name='conflicts.hasFunding'][value='yes']")); + + Utils.scrollToElement(driver, element1); + element1.click(); + + WebElement element2 = driver.findElement(By.cssSelector("button[data-test='submission-next']")); + + Utils.scrollToElement(driver, element2); + element2.click(); + + // Third step submission flow + + try { + wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.cssSelector(".wizard-step [level='2']")))); + } catch (NoSuchElementException e) { + + } + WebElement pageTitle = driver.findElement(By.cssSelector(".wizard-step [level='2']")); + assertEquals("3. Manuscript Files Upload", pageTitle.getText()); + + try { + wait.until(ExpectedConditions.visibilityOf(pageTitle)); + } catch (NoSuchElementException e) { + + } + + driver.findElement(By.cssSelector(/*"[data-test='upload-manuscripts']*/"input[type=\"file\"]")).sendKeys(Constants.fileManuscript); +// driver.findElement(By.cssSelector("[data-test='upload-supplementary'] input[type=\"file\"]")).sendKeys(Constants.fileSupplementary); +// driver.findElement(By.cssSelector("[data-test='upload-coverLetter'] input[type=\"file\"]")).sendKeys(Constants.fileCoverLetter); + + try { + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button[data-test='submission-next']"))); + } catch (NoSuchElementException e) { + + } + + WebElement element3 = driver.findElement(By.cssSelector("button[data-test='submission-next']")); + Utils.scrollToElement(driver, element3); + element3.click(); + + driver.findElement(By.xpath("//button[contains(.,'AGREE & SUBMIT')]")).click(); + + try { + wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//button[contains(.,'GO TO DASHBOARD')]"))); + } catch (NoSuchElementException e) { + + } + + driver.findElement(By.xpath("//button[contains(.,'GO TO DASHBOARD')]")).click(); + + } +} diff --git a/Automation/src/test/java/Utils.java b/Automation/src/test/java/Utils.java index cc31dadae8f24c486d4c45c9d146d3543956b3f6..7d10e9b50dd5f7bb91ba721c06512cf1e28ecec9 100644 --- a/Automation/src/test/java/Utils.java +++ b/Automation/src/test/java/Utils.java @@ -85,5 +85,12 @@ public class Utils { driver.findElement(By.xpath(".//button[contains(text(),'"+"CONFIRM"+"')]")).click(); } + + public static void scrollToElement(WebDriver driver, WebElement el) { + if (driver instanceof JavascriptExecutor) { + ((JavascriptExecutor) driver) + .executeScript("arguments[0].scrollIntoView(true);", el); + } + } } diff --git a/Dockerfile b/Dockerfile index 8bb801c8bb952fb053dc6ab9ad5d719022819bd6..88b5a40e2e356674b3875599e610feece9c8c5cc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,6 @@ RUN [ "yarn", "cache", "clean"] RUN [ "rm", "-rf", "/npm-packages-offline-cache"] WORKDIR ${HOME}/packages/xpub-faraday - ENV NODE_ENV "production" RUN echo $NODE_ENV diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js index e50d81e78664dd1caea593a658728fd21370c69a..fbfcf2db03ad8928dbf383f8b80c010fb256d2a0 100644 --- a/packages/component-faraday-selectors/src/index.js +++ b/packages/component-faraday-selectors/src/index.js @@ -174,4 +174,15 @@ export const pendingHEInvitation = (state, collectionId) => i.role === 'handlingEditor' && !i.hasAnswer, ) + +const hideCustomIdStatuses = ['draft', 'technicalChecks'] +export const newestFirstParseCustomId = items => + chain(items) + .orderBy(['created'], ['desc']) + .map(item => ({ + ...item, + customId: + !hideCustomIdStatuses.includes(get(item, 'status', 'draft')) && + item.customId, + })) .value() diff --git a/packages/component-faraday-ui/src/ManuscriptCard.js b/packages/component-faraday-ui/src/ManuscriptCard.js index f06c5557a6e8a5d442d6b230df00cc92b76b9370..269c0401842819645308600decec57ae403e711b 100644 --- a/packages/component-faraday-ui/src/ManuscriptCard.js +++ b/packages/component-faraday-ui/src/ManuscriptCard.js @@ -52,18 +52,23 @@ const ManuscriptCard = ({ </Row> )} <Row alignItems="center" justify="flex-start" mb={1}> - <Text customId mr={1}>{`ID ${customId}`}</Text> + {customId && <Text customId mr={1}>{`ID ${customId}`}</Text>} {submitted && ( <DateParser humanizeThreshold={0} timestamp={submitted}> - {timestamp => <Text mr={3}>Submitted on {timestamp}</Text>} + {(timestamp, timeAgo) => ( + <Text + mr={3} + >{`Submitted on ${timestamp} (${timeAgo} ago)`}</Text> + )} </DateParser> )} <Text>{manuscriptType.label || type}</Text> - {journal && ( - <Text journal ml={1}> - {journal} - </Text> - )} + {journal && + (manuscriptType.label || type) && ( + <Text journal ml={1}> + {journal} + </Text> + )} </Row> <Row alignItems="center" justify="flex-start" mb={1}> <H4>Handling editor</H4> diff --git a/packages/component-user-manager/src/Users.js b/packages/component-user-manager/src/Users.js index 581d7b87972085670892b8004f22cb54442a5861..9cc9c3f43fdda0bf00af9765aa5d28ca43bcb008 100644 --- a/packages/component-user-manager/src/Users.js +++ b/packages/component-user-manager/src/Users.js @@ -1,3 +1,5 @@ +const config = require('config') +const jwt = require('jsonwebtoken') const bodyParser = require('body-parser') const orcidRoutes = require('./routes/users/linkOrcid') @@ -167,6 +169,7 @@ const Users = app => { * @apiGroup Users * @apiSuccessExample {json} Success * HTTP/1.1 200 OK + * { users: * [{ * "id": "a6184463-b17a-42f8-b02b-ae1d755cdc6b", * "type": "user", @@ -201,6 +204,7 @@ const Users = app => { * "isSubmitting": false, * "isCorresponding": false, * }] + * } * @apiErrorExample {json} List errors * HTTP/1.1 403 Unauthorized */ @@ -209,9 +213,65 @@ const Users = app => { authBearer, require(`./routes/users/get`)(app.locals.models), ) + /** + * @api {post} /api/users Create user + * @apiGroup Users + * @apiParamExample {json} Body + * { + * "password": "currentPassword", + * "email": "email@example.com", + * "firstName": "John", + * "lastName": "Smith", + * "affiliation": "UCLA", + * "title": "Mr" + * } + * @apiSuccessExample {json} Success + * HTTP/1.1 200 OK + * { + * "id": "a6184463-b17a-42f8-b02b-ae1d755cdc6b", + * "type": "user", + * "admin": false, + * "email": "email@example.com", + * "teams": [], + * "username": "email@example.com", + * "fragments": [], + * "collections": [], + * "isConfirmed": true, + * "editorInChief": false, + * "handlingEditor": false, + * "notifications": { + * "email": { + * "system": true, + * "user": true + * } + * } + * } + * @apiErrorExample {json} Reset password errors + * HTTP/1.1 400 Bad Request + * HTTP/1.1 404 Not Found + */ + app.post( + '/api/users', + authorize, + require('./routes/users/post')(app.locals.models), + ) // register ORCID authentication strategy orcidRoutes(app) } +const authorize = async (req, res, next) => { + if (req.headers.authorization) { + const [, bToken] = req.headers.authorization.split(' ') + try { + const payload = jwt.verify(bToken, config.get('pubsweet-server.secret')) + req.user = payload.id + return next() + } catch (e) { + return res.status(403).json({ error: 'Unauthorized' }) + } + } + return next() +} + module.exports = Users diff --git a/packages/component-user-manager/src/routes/users/post.js b/packages/component-user-manager/src/routes/users/post.js new file mode 100644 index 0000000000000000000000000000000000000000..32870956242c4642678383795848b6bb96946d80 --- /dev/null +++ b/packages/component-user-manager/src/routes/users/post.js @@ -0,0 +1,52 @@ +const { pick } = require('lodash') +const Chance = require('chance') + +const chance = new Chance() + +module.exports = models => async (req, res) => { + if (req.user) { + const admin = await models.User.find(req.user) + if (!admin.admin) { + return res.status(403).json({ error: 'Unauthorized' }) + } + } else { + if (!req.body.agreeTC) { + return res.status(403).json({ + error: 'Terms & Conditions must be read and approved.', + }) + } + req.body = pick(req.body, [ + 'email', + 'title', + 'country', + 'firstName', + 'lastName', + 'password', + 'affiliation', + ]) + req.body = { + ...req.body, + admin: false, + isActive: true, + isConfirmed: false, + handlingEditor: false, + editorInChief: false, + username: req.body.email, + confirmationToken: chance.hash(), + notifications: { + email: { + system: true, + user: true, + }, + }, + } + } + let user = new models.User(req.body) + + try { + user = await user.save() + return res.status(201).json(user) + } catch (err) { + return res.status(400).json({ error: err.message }) + } +} diff --git a/packages/components-faraday/src/components/Dashboard/Dashboard.js b/packages/components-faraday/src/components/Dashboard/Dashboard.js index 82137f785d294edbe2d8cf5996a492652b6b348b..0c106443fd6d2da18ebbdce662c5d738bc6b8dd8 100644 --- a/packages/components-faraday/src/components/Dashboard/Dashboard.js +++ b/packages/components-faraday/src/components/Dashboard/Dashboard.js @@ -23,6 +23,6 @@ const Dashboard = ({ export default compose( withProps(({ dashboard, filterItems }) => ({ - dashboardItems: filterItems(dashboard.all), + dashboardItems: filterItems(dashboard), })), )(Dashboard) diff --git a/packages/components-faraday/src/components/Dashboard/DashboardPage.js b/packages/components-faraday/src/components/Dashboard/DashboardPage.js index 944329379b27e97f83a5d770b1a50ea49142eaa7..6831dbc0265ec953396fafa62fe49e8bae853af9 100644 --- a/packages/components-faraday/src/components/Dashboard/DashboardPage.js +++ b/packages/components-faraday/src/components/Dashboard/DashboardPage.js @@ -5,9 +5,12 @@ import { withJournal } from 'xpub-journal' import { ConnectPage } from 'xpub-connect' import { withRouter } from 'react-router-dom' import { compose, withContext } from 'recompose' -import { newestFirst, selectCurrentUser } from 'xpub-selectors' +import { selectCurrentUser } from 'xpub-selectors' -import { getUserPermissions } from 'pubsweet-component-faraday-selectors' +import { + getUserPermissions, + newestFirstParseCustomId, +} from 'pubsweet-component-faraday-selectors' import { Dashboard } from './' import { priorityFilter, orderFilter, withFiltersHOC } from '../Filters' @@ -18,24 +21,8 @@ export default compose( state => { const { collections, conversion } = state const currentUser = selectCurrentUser(state) - const sortedCollections = newestFirst(collections) + const dashboard = newestFirstParseCustomId(collections) - const dashboard = { - owner: sortedCollections.filter( - collection => - collection.owners && - collection.owners.some(owner => owner.id === currentUser.id), - ), - reviewer: sortedCollections.filter( - collection => - collection.reviewers && - collection.reviewers.some( - reviewer => reviewer && reviewer.user === currentUser.id, - ), - ), - - all: sortedCollections, - } const userPermissions = getUserPermissions(state) return { dashboard, diff --git a/packages/components-faraday/src/components/SignUp/utils.js b/packages/components-faraday/src/components/SignUp/utils.js index bf27a045194a52240357280db2cd268a42a4f497..3a9fd998810f022e1f270db62c10ab020a8bf29b 100644 --- a/packages/components-faraday/src/components/SignUp/utils.js +++ b/packages/components-faraday/src/components/SignUp/utils.js @@ -5,28 +5,8 @@ import { loginUser } from 'pubsweet-component-login/actions' import { handleFormError } from '../utils' -const generatePasswordHash = () => - Array.from({ length: 4 }, () => - Math.random() - .toString(36) - .slice(4), - ).join('') - export const parseSignupAuthor = ({ token, confirmPassword, ...values }) => ({ ...values, - admin: false, - isActive: true, - isConfirmed: false, - editorInChief: false, - handlingEditor: false, - username: values.email, - confirmationToken: generatePasswordHash(), - notifications: { - email: { - system: true, - user: true, - }, - }, }) export const parseSearchParams = url => { diff --git a/packages/xpub-faraday/app/config/journal/metadata.js b/packages/xpub-faraday/app/config/journal/metadata.js index a204afcbc11b0e9a967180450991778cfde39ddf..d23e29ac87bd7daba4425925e1969f69a0beeecc 100644 --- a/packages/xpub-faraday/app/config/journal/metadata.js +++ b/packages/xpub-faraday/app/config/journal/metadata.js @@ -2,7 +2,7 @@ module.exports = { issn: '2474-7394', logo: '/assets/logo-hindawi@2x.png', nameText: 'Bioinorganic Chemistry and Applications', - email: 'bca.support@hindawi.com', + email: process.env.EMAIL_SENDER || 'bca.support@hindawi.com', mts: { doctype: 'article SYSTEM "JATS-archivearticle1-mathml3.dtd"', dtdVersion: '1.1d1', diff --git a/packages/xpub-faraday/webpack/webpack.production.config.js b/packages/xpub-faraday/webpack/webpack.production.config.js index 0d39669864461e3188c03bf231076559a84d6ab4..c96a217e987c9dbd66eae7406e58b9eb8e0160a8 100644 --- a/packages/xpub-faraday/webpack/webpack.production.config.js +++ b/packages/xpub-faraday/webpack/webpack.production.config.js @@ -48,14 +48,10 @@ module.exports = [ }); var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f); - })(window, document, 'script', 'dataLayer', '${ - process.env.GA_KEY - }');</script> + })(window, document, 'script', 'dataLayer', 'GTM-5V2LT8L');</script> <!-- End Google Tag Manager -->`, gaBody: ` <!-- Google Tag Manager (noscript) --> - <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${ - process.env.GA_KEY - }" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> + <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5V2LT8L" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) -->`, }), new webpack.DefinePlugin({ diff --git a/scripts/wait-for-it.sh b/scripts/wait-for-it.sh new file mode 100755 index 0000000000000000000000000000000000000000..ea896a848ceabb0234802257d1fb78ba6eb1b4cb --- /dev/null +++ b/scripts/wait-for-it.sh @@ -0,0 +1,178 @@ +#!/usr/bin/env bash +# Use this script to test if a given TCP host/port are available + +cmdname=$(basename $0) + +echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } + +usage() +{ + cat << USAGE >&2 +Usage: + $cmdname host:port [-s] [-t timeout] [-- command args] + -h HOST | --host=HOST Host or IP under test + -p PORT | --port=PORT TCP port under test + Alternatively, you specify the host and port as host:port + -s | --strict Only execute subcommand if the test succeeds + -q | --quiet Don't output any status messages + -t TIMEOUT | --timeout=TIMEOUT + Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit 1 +} + +wait_for() +{ + if [[ $TIMEOUT -gt 0 ]]; then + echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" + else + echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" + fi + start_ts=$(date +%s) + while : + do + if [[ $ISBUSY -eq 1 ]]; then + nc -z $HOST $PORT + result=$? + else + (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 + result=$? + fi + if [[ $result -eq 0 ]]; then + end_ts=$(date +%s) + echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" + break + fi + sleep 1 + done + return $result +} + +wait_for_wrapper() +{ + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 + if [[ $QUIET -eq 1 ]]; then + timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & + else + timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & + fi + PID=$! + trap "kill -INT -$PID" INT + wait $PID + RESULT=$? + if [[ $RESULT -ne 0 ]]; then + echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" + fi + return $RESULT +} + +# process arguments +while [[ $# -gt 0 ]] +do + case "$1" in + *:* ) + hostport=(${1//:/ }) + HOST=${hostport[0]} + PORT=${hostport[1]} + shift 1 + ;; + --child) + CHILD=1 + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -s | --strict) + STRICT=1 + shift 1 + ;; + -h) + HOST="$2" + if [[ $HOST == "" ]]; then break; fi + shift 2 + ;; + --host=*) + HOST="${1#*=}" + shift 1 + ;; + -p) + PORT="$2" + if [[ $PORT == "" ]]; then break; fi + shift 2 + ;; + --port=*) + PORT="${1#*=}" + shift 1 + ;; + -t) + TIMEOUT="$2" + if [[ $TIMEOUT == "" ]]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + CLI=("$@") + break + ;; + --help) + usage + ;; + *) + echoerr "Unknown argument: $1" + usage + ;; + esac +done + +if [[ "$HOST" == "" || "$PORT" == "" ]]; then + echoerr "Error: you need to provide a host and port to test." + usage +fi + +TIMEOUT=${TIMEOUT:-15} +STRICT=${STRICT:-0} +CHILD=${CHILD:-0} +QUIET=${QUIET:-0} + +# check to see if timeout is from busybox? +# check to see if timeout is from busybox? +TIMEOUT_PATH=$(realpath $(which timeout)) +if [[ $TIMEOUT_PATH =~ "busybox" ]]; then + ISBUSY=1 + BUSYTIMEFLAG="-t" +else + ISBUSY=0 + BUSYTIMEFLAG="" +fi + +if [[ $CHILD -gt 0 ]]; then + wait_for + RESULT=$? + exit $RESULT +else + if [[ $TIMEOUT -gt 0 ]]; then + wait_for_wrapper + RESULT=$? + else + wait_for + RESULT=$? + fi +fi + +if [[ $CLI != "" ]]; then + if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then + echoerr "$cmdname: strict mode, refusing to execute subprocess" + exit $RESULT + fi + exec "${CLI[@]}" +else + exit $RESULT +fi +