diff --git a/build-tools/src/main/resources/zanata-build-tools/versions-rules.xml b/build-tools/src/main/resources/zanata-build-tools/versions-rules.xml
new file mode 100644
index 0000000000..c4e47caf9e
--- /dev/null
+++ b/build-tools/src/main/resources/zanata-build-tools/versions-rules.xml
@@ -0,0 +1,8 @@
+
+
+
+ .*[-_\.](alpha|Alpha|ALPHA|b|beta|Beta|BETA|cr|CR|rc|RC|M|EA)[-_\.]?[0-9]*
+
+
diff --git a/parent/pom.xml b/parent/pom.xml
index b2583cd3ed..a2eec5884d 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -596,7 +596,17 @@
org.codehaus.mojo
versions-maven-plugin
- 2.2
+ 2.5
+
+ classpath:///zanata-build-tools/versions-rules.xml
+
+
+
+ org.zanata
+ build-tools
+ ${project.version}
+
+
@@ -843,6 +853,19 @@
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.1
+ true
+
+
+ https://oss.sonatype.org/
+
+ sonatype-staging
+
+
+
org.apache.maven.plugins
diff --git a/server/services/src/main/java/org/zanata/action/ActivateAction.java b/server/services/src/main/java/org/zanata/action/ActivateAction.java
index 2bf5a1a9d3..857e3b9417 100644
--- a/server/services/src/main/java/org/zanata/action/ActivateAction.java
+++ b/server/services/src/main/java/org/zanata/action/ActivateAction.java
@@ -48,21 +48,34 @@ public class ActivateAction implements Serializable {
private static final long serialVersionUID = -8079131168179421345L;
private static final int LINK_ACTIVE_DAYS = 1;
- @Inject
+
private GroupedConversation conversation;
- @Inject
private AccountActivationKeyDAO accountActivationKeyDAO;
- @Inject
private IdentityManager identityManager;
- @Inject
private UrlUtil urlUtil;
- @Inject
+
private FacesMessages facesMessages;
private String activationKey;
private HAccountActivationKey key;
private String resetPasswordKey;
// @Begin(join = true)
+ @Inject
+ public ActivateAction(GroupedConversation conversation,
+ AccountActivationKeyDAO accountActivationKeyDAO,
+ IdentityManager identityManager,
+ UrlUtil urlUtil, FacesMessages facesMessages) {
+ this.conversation = conversation;
+ this.accountActivationKeyDAO = accountActivationKeyDAO;
+ this.identityManager = identityManager;
+ this.urlUtil = urlUtil;
+ this.facesMessages = facesMessages;
+ }
+
+ @SuppressWarnings("unused")
+ public ActivateAction() {
+ }
+
public void validateActivationKey() {
if (getActivationKey() == null) {
throw new KeyNotFoundException("null activation key");
diff --git a/server/services/src/test/java/org/zanata/action/ActivateActionTest.java b/server/services/src/test/java/org/zanata/action/ActivateActionTest.java
new file mode 100644
index 0000000000..c370d90e51
--- /dev/null
+++ b/server/services/src/test/java/org/zanata/action/ActivateActionTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2018, Red Hat, Inc. and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.zanata.action;
+
+import org.apache.deltaspike.core.api.scope.GroupedConversation;
+import org.jglue.cdiunit.InRequestScope;
+import org.jglue.cdiunit.InSessionScope;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.zanata.dao.AccountActivationKeyDAO;
+import org.zanata.exception.ActivationLinkExpiredException;
+import org.zanata.exception.KeyNotFoundException;
+import org.zanata.model.HAccount;
+import org.zanata.model.HAccountActivationKey;
+import org.zanata.seam.security.IdentityManager;
+import org.zanata.test.CdiUnitRunner;
+import org.zanata.ui.faces.FacesMessages;
+import org.zanata.util.UrlUtil;
+
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import java.util.Date;
+
+import static org.mockito.Mockito.when;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author djansen djansen@redhat.com
+ */
+@InSessionScope
+@InRequestScope
+@RunWith(CdiUnitRunner.class)
+public class ActivateActionTest {
+
+ @Produces
+ @Mock
+ private GroupedConversation conversation;
+ @Produces
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private AccountActivationKeyDAO accountActivationKeyDAO;
+ @Produces
+ @Mock
+ private IdentityManager identityManager;
+ @Produces
+ @Mock
+ private UrlUtil urlUtil;
+ @Produces
+ @Mock
+ private FacesMessages facesMessages;
+ @Inject
+ private ActivateAction action;
+
+ @Before
+ public void before() {
+ action = new ActivateAction(conversation, accountActivationKeyDAO,
+ identityManager, urlUtil, facesMessages);
+ }
+
+ @Test
+ public void nullKeyTest() {
+ action.setActivationKey(null);
+ try {
+ action.validateActivationKey();
+ Assert.fail("Expected KeyNotFoundException");
+ } catch (KeyNotFoundException knfe) {
+ assertThat(knfe.getMessage()).contains("null activation key");
+ }
+ }
+
+ @Test
+ public void keyNoLongerExists() {
+ action.setActivationKey("1234567890");
+ when(accountActivationKeyDAO.findById(action.getActivationKey(), false))
+ .thenReturn(null);
+ try {
+ action.validateActivationKey();
+ Assert.fail("Expected KeyNotFoundException");
+ } catch (KeyNotFoundException knfe) {
+ assertThat(knfe.getMessage()).contains("activation key: 1234567890");
+ }
+ }
+
+ @Test
+ public void expiredKeyTest() {
+ HAccountActivationKey key = new HAccountActivationKey();
+ key.setCreationDate(new Date(0L));
+ action.setActivationKey("1234567890");
+ when(accountActivationKeyDAO.findById(action.getActivationKey(), false))
+ .thenReturn(key);
+ try {
+ action.validateActivationKey();
+ Assert.fail("Expected ActivationLinkExpiredException");
+ } catch (ActivationLinkExpiredException alee) {
+ assertThat(alee.getMessage())
+ .contains("Activation link expired:1234567890");
+ }
+ }
+
+ @Test
+ public void activateTest() {
+ HAccountActivationKey key = new HAccountActivationKey();
+ key.setCreationDate(new Date());
+ HAccount hAccount = new HAccount();
+ hAccount.setUsername("Aloy");
+ action.setActivationKey("1234567890");
+ when(accountActivationKeyDAO.findById(action.getActivationKey(), false))
+ .thenReturn(key);
+ action.validateActivationKey();
+ // TODO ZNTA-2365 action.activate();
+ }
+}
diff --git a/server/services/src/test/java/org/zanata/adapter/AdapterUtilsTest.java b/server/services/src/test/java/org/zanata/adapter/AdapterUtilsTest.java
new file mode 100644
index 0000000000..6f482b6b31
--- /dev/null
+++ b/server/services/src/test/java/org/zanata/adapter/AdapterUtilsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018, Red Hat, Inc. and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.zanata.adapter;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.zanata.exception.FileFormatAdapterException;
+
+import java.net.URI;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Damian Jansen djansen@redhat.com
+ */
+public class AdapterUtilsTest {
+
+ @Test
+ public void testNull() {
+ try {
+ AdapterUtils.readStream(URI.create(""));
+ Assert.fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException iae) {
+ assertThat(iae.getMessage()).contains("absolute");
+ }
+ }
+
+ @Test
+ public void testMalformed() {
+ try {
+ AdapterUtils.readStream(URI
+ .create("http://2aff:eaff:eaff:7aff:8aff:5aff:faff:eaff:8080/foo"));
+ Assert.fail("Expected FileFormatAdapterException");
+ } catch (FileFormatAdapterException ffae) {
+ assertThat(ffae.getMessage()).contains("malformed");
+ }
+ }
+
+ @Test
+ public void testAccess() {
+ try {
+ AdapterUtils.readStream(URI.create("http://tmp"));
+ Assert.fail("Expected FileFormatAdapterException");
+ } catch (FileFormatAdapterException ffae) {
+ assertThat(ffae.getMessage()).contains("stream");
+ }
+ }
+}
diff --git a/server/zanata-frontend/pom.xml b/server/zanata-frontend/pom.xml
index 833dff6616..ad014c5dc8 100644
--- a/server/zanata-frontend/pom.xml
+++ b/server/zanata-frontend/pom.xml
@@ -133,6 +133,7 @@
src/dist
+ messages/*.json
editor.*.cache.js
editor.*.cache.css
editor.*.cache.css.map
diff --git a/server/zanata-frontend/src/app/config.js b/server/zanata-frontend/src/app/config.js
index 2d734e454d..028ff5a369 100644
--- a/server/zanata-frontend/src/app/config.js
+++ b/server/zanata-frontend/src/app/config.js
@@ -8,6 +8,12 @@ const rawConfig = window.config
const config = mapValues(rawConfig || {}, (value) =>
isJsonString(value) ? JSON.parse(value) : value)
+export const DEFAULT_LOCALE = {
+ localeId: 'en-US',
+ name: 'English',
+ isRTL: false
+}
+
// URL this app is deployed to
export const appUrl = config.appUrl || ''
@@ -27,3 +33,4 @@ export const isAdmin = config.permission
: false
export const user = config.user
export const allowRegister = config.allowRegister || false
+export const appLocale = config.appLocale || DEFAULT_LOCALE['localeId']
diff --git a/server/zanata-frontend/src/app/editor/actions/header-action-types.js b/server/zanata-frontend/src/app/editor/actions/header-action-types.js
index bd1b3682eb..66f0ec5ec5 100644
--- a/server/zanata-frontend/src/app/editor/actions/header-action-types.js
+++ b/server/zanata-frontend/src/app/editor/actions/header-action-types.js
@@ -4,6 +4,7 @@ export const TOGGLE_INFO_PANEL = 'TOGGLE_INFO_PANEL'
export const TOGGLE_HEADER = 'TOGGLE_HEADER'
export const TOGGLE_KEY_SHORTCUTS = 'TOGGLE_KEY_SHORTCUTS'
export const UI_LOCALES_FETCHED = 'UI_LOCALES_FETCHED'
+export const APP_LOCALE_FETCHED = 'APP_LOCALE_FETCHED'
export const CHANGE_UI_LOCALE = 'CHANGE_UI_LOCALE'
export const DOCUMENT_SELECTED = 'DOCUMENT_SELECTED'
export const LOCALE_SELECTED = 'LOCALE_SELECTED'
@@ -12,3 +13,6 @@ export const HEADER_DATA_FETCHED = 'HEADER_DATA_FETCHED'
export const USER_PERMISSION_REQUEST = 'USER_PERMISSION_REQUEST'
export const USER_PERMISSION_SUCCESS = 'USER_PERMISSION_SUCCESS'
export const USER_PERMISSION_FAILURE = 'USER_PERMISSION_FAILURE'
+export const LOCALE_MESSAGES_REQUEST = 'LOCALE_MESSAGES_REQUEST'
+export const LOCALE_MESSAGES_SUCCESS = 'LOCALE_MESSAGES_SUCCESS'
+export const LOCALE_MESSAGES_FAILURE = 'LOCALE_MESSAGES_FAILURE'
diff --git a/server/zanata-frontend/src/app/editor/actions/header-actions.js b/server/zanata-frontend/src/app/editor/actions/header-actions.js
index 880d01e52a..30f82504f4 100644
--- a/server/zanata-frontend/src/app/editor/actions/header-actions.js
+++ b/server/zanata-frontend/src/app/editor/actions/header-actions.js
@@ -2,6 +2,7 @@
import {
fetchStatistics,
fetchLocales,
+ fetchI18nLocale,
fetchMyInfo,
fetchProjectInfo,
fetchDocuments,
@@ -15,6 +16,7 @@ import {
TOGGLE_HEADER,
TOGGLE_KEY_SHORTCUTS,
UI_LOCALES_FETCHED,
+ APP_LOCALE_FETCHED,
CHANGE_UI_LOCALE,
DOCUMENT_SELECTED,
LOCALE_SELECTED,
@@ -40,6 +42,7 @@ const unwrapResponse = (_dispatch, _errorMsg, response) => {
}
export const uiLocaleFetched = createAction(UI_LOCALES_FETCHED)
+export const appLocaleFetched = createAction(APP_LOCALE_FETCHED)
export function fetchUiLocales () {
return (dispatch) => {
@@ -54,6 +57,13 @@ export function fetchUiLocales () {
}
}
+// fetches react-intl translation json files for app i18n
+export function fetchAppLocale (locale) {
+ return (dispatch) => {
+ dispatch(fetchI18nLocale(locale))
+ }
+}
+
export const changeUiLocale = createAction(CHANGE_UI_LOCALE)
const decodeDocId = (docId) => {
diff --git a/server/zanata-frontend/src/app/editor/api/index.js b/server/zanata-frontend/src/app/editor/api/index.js
index 9754eacd23..742fc27db8 100644
--- a/server/zanata-frontend/src/app/editor/api/index.js
+++ b/server/zanata-frontend/src/app/editor/api/index.js
@@ -17,12 +17,15 @@ import {
import {
USER_PERMISSION_REQUEST,
USER_PERMISSION_SUCCESS,
- USER_PERMISSION_FAILURE
+ USER_PERMISSION_FAILURE,
+ LOCALE_MESSAGES_REQUEST,
+ LOCALE_MESSAGES_SUCCESS,
+ LOCALE_MESSAGES_FAILURE
} from '../actions/header-action-types'
import { buildAPIRequest, getJsonHeaders } from '../../actions/common-actions'
import { CALL_API } from 'redux-api-middleware'
import { includes } from 'lodash'
-import { apiUrl, serverUrl } from '../../config'
+import { apiUrl, serverUrl, appUrl } from '../../config'
import stableStringify from 'faster-stable-stringify'
export const dashboardUrl = serverUrl + '/dashboard'
@@ -83,6 +86,27 @@ export function fetchLocales () {
})
}
+export function fetchI18nLocale (locale) {
+ const endpoint = `${appUrl}/messages/${locale}.json`
+ const apiTypes = [
+ LOCALE_MESSAGES_REQUEST,
+ {
+ type: LOCALE_MESSAGES_SUCCESS,
+ payload: (_action, _state, res) => {
+ const contentType = res.headers.get('Content-Type')
+ if (contentType && includes(contentType, 'json')) {
+ return res.json().then((json) => {
+ return json
+ })
+ }
+ }
+ },
+ LOCALE_MESSAGES_FAILURE]
+ return {
+ [CALL_API]: buildAPIRequest(endpoint, 'GET', getJsonHeaders(), apiTypes)
+ }
+}
+
export function fetchMyInfo () {
const userUrl = `${apiUrl}/user`
return fetch(userUrl, {
diff --git a/server/zanata-frontend/src/app/editor/components/TranslatingIndicator/TranslatingIndicator.test.js b/server/zanata-frontend/src/app/editor/components/TranslatingIndicator/TranslatingIndicator.test.js
index 8f9884dbf7..3c7b3cfef3 100644
--- a/server/zanata-frontend/src/app/editor/components/TranslatingIndicator/TranslatingIndicator.test.js
+++ b/server/zanata-frontend/src/app/editor/components/TranslatingIndicator/TranslatingIndicator.test.js
@@ -1,27 +1,30 @@
-
import React from 'react'
import * as ReactDOMServer from 'react-dom/server'
import TranslatingIndicator from '.'
import { Icon } from '../../../components'
import { Row } from 'react-bootstrap'
+import { IntlProvider } from 'react-intl'
-describe('TranslatingIndicatorTest', () => {
- it('TranslatingIndicator markup', () => {
+/* global describe expect it */
+describe('TranslatingIndicator', () => {
+ it('renders default markup', () => {
const gettextCatalog = {
getString: (key) => {
return key
}
}
const actual = ReactDOMServer.renderToStaticMarkup(
- )
+
+
+ )
const expected = ReactDOMServer.renderToStaticMarkup(
/* eslint-disable max-len */
-