diff --git a/docs/release-notes.md b/docs/release-notes.md index 9c60f31251..1b86b4b0b5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -30,6 +30,7 @@ * [1224912] (https://bugzilla.redhat.com/show_bug.cgi?id=1224912) - Filter "Last modified by translators other than " * [1213630](https://bugzilla.redhat.com/show_bug.cgi?id=1213630) - Webhook header needs to include cryptographic signature in header for identification * [1214502](https://bugzilla.redhat.com/show_bug.cgi?id=1214502) - RFE: Grant project creation permission to certain sets of users +* [ZNTA-555](https://zanata.atlassian.net/browse/ZNTA-555) - Internal "user request management" and tracking ----------------------- diff --git a/functional-test/src/main/java/org/zanata/page/languages/LanguagePage.java b/functional-test/src/main/java/org/zanata/page/languages/LanguagePage.java index b057438691..3161ad6ca7 100644 --- a/functional-test/src/main/java/org/zanata/page/languages/LanguagePage.java +++ b/functional-test/src/main/java/org/zanata/page/languages/LanguagePage.java @@ -45,9 +45,9 @@ public class LanguagePage extends BasePage { private By contactCoordinatorsButton = - By.linkText("Contact Coordinators"); + By.id("contact-coordinator"); private By saveButton = By.id("save-button"); - private By moreActions = By.className("dropdown__toggle"); + private By moreActions = By.id("more-action"); private By enableByDefault = By.id("enable-by-default"); private By membersTab = By.id("members_tab"); private By settingsTab = By.id("settings_tab"); diff --git a/zanata-model/src/main/java/org/zanata/model/Request.java b/zanata-model/src/main/java/org/zanata/model/Request.java index 3900563b6f..7a69900ee6 100644 --- a/zanata-model/src/main/java/org/zanata/model/Request.java +++ b/zanata-model/src/main/java/org/zanata/model/Request.java @@ -116,6 +116,11 @@ public static class EntityListener { @PrePersist private void prePersist(Request request) { request.validFrom = new Date(); + //make sure validFrom is not after validTo(set from service) + if (request.validTo != null + && (request.validFrom.after(request.validTo))) { + request.validFrom = request.validTo; + } } } } diff --git a/zanata-war/src/main/java/org/zanata/action/LanguageAction.java b/zanata-war/src/main/java/org/zanata/action/LanguageAction.java index 114d0c74af..3e5fcbe9f0 100644 --- a/zanata-war/src/main/java/org/zanata/action/LanguageAction.java +++ b/zanata-war/src/main/java/org/zanata/action/LanguageAction.java @@ -168,7 +168,7 @@ public List getRequests() { } if (identity != null && identity.hasPermission(locale, "manage-language-team")) { - return requestServiceImpl.getOutstandingLanguageRequests( + return requestServiceImpl.getPendingLanguageRequests( locale.getLocaleId()); } return Lists.newArrayList(); diff --git a/zanata-war/src/main/java/org/zanata/action/LanguageJoinAction.java b/zanata-war/src/main/java/org/zanata/action/LanguageJoinAction.java index a56b184bb8..967989d37b 100644 --- a/zanata-war/src/main/java/org/zanata/action/LanguageJoinAction.java +++ b/zanata-war/src/main/java/org/zanata/action/LanguageJoinAction.java @@ -156,7 +156,7 @@ public void requestAsReviewer() { public void requestAsCoordinator() { processRequest(false, false, true); } - + private void processRequest(boolean isRequestAsTranslator, boolean isRequestAsReviewer, boolean isRequestAsCoordinator) { @@ -206,7 +206,8 @@ private void sendRequestEmail(boolean isRequestAsCoordinator, } public boolean isUserAlreadyRequest() { - return requestServiceImpl.isRequestExist(authenticatedAccount, getLocale()); + return requestServiceImpl.isLanguageRequestExist(authenticatedAccount, + getLocale()); } public void cancelRequest() { @@ -219,7 +220,7 @@ public void cancelRequest() { + authenticatedAccount.getUsername() + "}"; requestServiceImpl.updateLanguageRequest(languageRequest.getId(), authenticatedAccount, RequestState.CANCELLED, comment); - + facesMessages.addGlobal(msgs.format("jsf.language.request.cancelled", authenticatedAccount.getUsername())); } diff --git a/zanata-war/src/main/java/org/zanata/dao/LanguageRequestDAO.java b/zanata-war/src/main/java/org/zanata/dao/LanguageRequestDAO.java index 9cd2ab003a..afda0bfe48 100644 --- a/zanata-war/src/main/java/org/zanata/dao/LanguageRequestDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/LanguageRequestDAO.java @@ -1,21 +1,16 @@ package org.zanata.dao; -import com.google.common.collect.Lists; import org.hibernate.Query; +import org.hibernate.Session; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.zanata.common.LocaleId; import org.zanata.model.HAccount; -import org.zanata.model.HLocale; import org.zanata.model.LanguageRequest; -import org.zanata.model.LocaleRole; -import org.zanata.model.type.RequestState; -import javax.annotation.Nullable; import java.util.List; -import java.util.Set; /** * @author Alex Eng aeng@redhat.com @@ -29,7 +24,11 @@ public LanguageRequestDAO() { super(LanguageRequest.class); } - public LanguageRequest findRequesterOutstandingRequests(HAccount requester, + public LanguageRequestDAO(Session session) { + super(LanguageRequest.class, session); + } + + public LanguageRequest findRequesterPendingRequests(HAccount requester, LocaleId localeId) { String query = "from LanguageRequest req where req.locale.localeId = :localeId and req.request.requester.id = :requesterId and req.request.validTo is null"; @@ -41,14 +40,14 @@ public LanguageRequest findRequesterOutstandingRequests(HAccount requester, return (LanguageRequest) q.uniqueResult(); } - public List findOutstandingRequests( + public List findPendingRequests( List localeIds) { String query = "from LanguageRequest req where req.request.validTo is null and req.locale.localeId in (:localeIds)"; Query q = getSession().createQuery(query) .setParameterList("localeIds", localeIds) .setCacheable(true).setComment( - "requestDAO.findOutstandingRequests"); + "requestDAO.findPendingRequests"); return q.list(); } } diff --git a/zanata-war/src/main/java/org/zanata/dao/RequestDAO.java b/zanata-war/src/main/java/org/zanata/dao/RequestDAO.java index 180c7dbcb2..d2adf49c6c 100644 --- a/zanata-war/src/main/java/org/zanata/dao/RequestDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/RequestDAO.java @@ -1,11 +1,16 @@ package org.zanata.dao; +import org.hibernate.Query; +import org.hibernate.Session; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; +import org.zanata.model.LanguageRequest; import org.zanata.model.Request; +import java.util.List; + /** * @author Alex Eng aeng@redhat.com */ @@ -18,7 +23,31 @@ public RequestDAO() { super(Request.class); } + public RequestDAO(Session session) { + super(Request.class, session); + } + public Request getById(Long requestId) { return findById(requestId); } + + public List getByEntityId(String entityId) { + String query = + "from Request req where req.entityId= :entityId order by req.validFrom"; + Query q = getSession().createQuery(query) + .setParameter("entityId", entityId) + .setCacheable(true).setComment( + "requestDAO.getByEntityId"); + return q.list(); + } + + public Request getPendingRequestByEntityId(String entityId) { + String query = + "from Request req where req.entityId= :entityId and req.validTo is null"; + Query q = getSession().createQuery(query) + .setParameter("entityId", entityId) + .setCacheable(true).setComment( + "requestDAO.getPendingRequestByEntityId"); + return (Request) q.uniqueResult(); + } } diff --git a/zanata-war/src/main/java/org/zanata/service/RequestService.java b/zanata-war/src/main/java/org/zanata/service/RequestService.java index f08b0cc91e..c6d47dfef3 100644 --- a/zanata-war/src/main/java/org/zanata/service/RequestService.java +++ b/zanata-war/src/main/java/org/zanata/service/RequestService.java @@ -57,7 +57,7 @@ LanguageRequest createLanguageRequest(HAccount requester, * @param requester * @param locale */ - boolean isRequestExist(HAccount requester, HLocale locale); + boolean isLanguageRequestExist(HAccount requester, HLocale locale); /** * Update join language request @@ -78,7 +78,7 @@ void updateLanguageRequest(Long requestId, HAccount actor, /** * Get pending language request for user - * + * * @param localeId */ LanguageRequest getPendingLanguageRequests(HAccount account, @@ -88,6 +88,18 @@ LanguageRequest getPendingLanguageRequests(HAccount account, * * @param Get outstanding language requests on languages */ - List getOutstandingLanguageRequests( + List getPendingLanguageRequests( LocaleId... localeIds); + + /** + * Return pending request by entityId + * @param entityId + */ + Request getPendingRequestByEntityId(String entityId); + + /** + * Return request including history by entityId + * @param entityId + */ + List getRequestByEntityId(String entityId); } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/RequestServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/RequestServiceImpl.java index dc69d07d90..3bb991a308 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/RequestServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/RequestServiceImpl.java @@ -41,7 +41,6 @@ import org.zanata.util.Event; import javax.persistence.EntityNotFoundException; -import java.sql.Timestamp; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -72,7 +71,7 @@ public LanguageRequest createLanguageRequest(HAccount requester, //of the same requester, account and locale LanguageRequest languageRequest = - languageRequestDAO.findRequesterOutstandingRequests(requester, + languageRequestDAO.findRequesterPendingRequests(requester, locale.getLocaleId()); if (languageRequest != null) { @@ -92,10 +91,10 @@ public LanguageRequest createLanguageRequest(HAccount requester, } @Override - public boolean isRequestExist(HAccount requester, HLocale locale) { + public boolean isLanguageRequestExist(HAccount requester, HLocale locale) { LanguageRequest languageRequest = - languageRequestDAO.findRequesterOutstandingRequests(requester, - locale.getLocaleId()); + languageRequestDAO.findRequesterPendingRequests(requester, + locale.getLocaleId()); return languageRequest != null; } @@ -142,15 +141,25 @@ public LanguageRequest getLanguageRequest(Long id) { @Override public LanguageRequest getPendingLanguageRequests(HAccount account, LocaleId localeId) { - return languageRequestDAO.findRequesterOutstandingRequests( - account, localeId); + return languageRequestDAO.findRequesterPendingRequests( + account, localeId); } @Override - public List getOutstandingLanguageRequests( + public List getPendingLanguageRequests( LocaleId... localeIds) { return languageRequestDAO - .findOutstandingRequests(Lists.newArrayList(localeIds)); + .findPendingRequests(Lists.newArrayList(localeIds)); + } + + @Override + public Request getPendingRequestByEntityId(String entityId) { + return requestDAO.getPendingRequestByEntityId(entityId); + } + + @Override + public List getRequestByEntityId(String entityId) { + return requestDAO.getByEntityId(entityId); } /** diff --git a/zanata-war/src/main/webapp/language/language.xhtml b/zanata-war/src/main/webapp/language/language.xhtml index 8414e4e84c..60c23394b8 100644 --- a/zanata-war/src/main/webapp/language/language.xhtml +++ b/zanata-war/src/main/webapp/language/language.xhtml @@ -189,29 +189,30 @@ - -
  • - - - - - - -
  • +
  • + + + + + + +
  • + +
  • + + + diff --git a/zanata-war/src/test/java/org/zanata/email/EmailStrategyTest.java b/zanata-war/src/test/java/org/zanata/email/EmailStrategyTest.java index fc6532278c..c992c0aa5a 100644 --- a/zanata-war/src/test/java/org/zanata/email/EmailStrategyTest.java +++ b/zanata-war/src/test/java/org/zanata/email/EmailStrategyTest.java @@ -292,8 +292,6 @@ public void requestToJoinLanguage() throws Exception { assertThat(html).contains(msgs.format( "jsf.email.joinrequest.UserRequestingToJoin", fromName, fromLoginName, localeId, localeNativeName)); - assertThat(html).contains( - htmlMessage); assertThat(html).contains( serverPath + "/language/view/" + localeId); } diff --git a/zanata-war/src/test/java/org/zanata/service/impl/RequestServiceImplTest.java b/zanata-war/src/test/java/org/zanata/service/impl/RequestServiceImplTest.java new file mode 100644 index 0000000000..b098da3219 --- /dev/null +++ b/zanata-war/src/test/java/org/zanata/service/impl/RequestServiceImplTest.java @@ -0,0 +1,157 @@ +package org.zanata.service.impl; + +import org.dbunit.operation.DatabaseOperation; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.zanata.ZanataDbunitJpaTest; +import org.zanata.dao.AccountDAO; +import org.zanata.dao.LanguageRequestDAO; +import org.zanata.dao.LocaleDAO; +import org.zanata.dao.RequestDAO; +import org.zanata.events.RequestUpdatedEvent; +import org.zanata.model.HAccount; +import org.zanata.model.HLocale; +import org.zanata.model.LanguageRequest; +import org.zanata.model.Request; +import org.zanata.model.type.RequestState; +import org.zanata.model.type.RequestType; +import org.zanata.seam.SeamAutowire; +import org.zanata.util.Event; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.verify; + +/** + * @author Alex Eng aeng@redhat.com + */ +public class RequestServiceImplTest extends ZanataDbunitJpaTest { + private SeamAutowire seam = SeamAutowire.instance(); + + private RequestServiceImpl service; + + private RequestDAO requestDAO; + + private LanguageRequestDAO languageRequestDAO; + + private AccountDAO accountDAO; + + private LocaleDAO localeDAO; + + @Mock + private Event requestUpdatedEvent; + + @Override + protected void prepareDBUnitOperations() { + beforeTestOperations.add(new DataSetOperation( + "org/zanata/test/model/ClearAllTables.dbunit.xml", + DatabaseOperation.CLEAN_INSERT)); + beforeTestOperations.add(new DataSetOperation( + "org/zanata/test/model/AccountData.dbunit.xml", + DatabaseOperation.CLEAN_INSERT)); + beforeTestOperations.add(new DataSetOperation( + "org/zanata/test/model/LocalesData.dbunit.xml", + DatabaseOperation.CLEAN_INSERT)); + } + + @Before + public void beforeMethod() throws Exception { + MockitoAnnotations.initMocks(this); + seam.reset(); + requestDAO = new RequestDAO(getSession()); + languageRequestDAO = new LanguageRequestDAO(getSession()); + accountDAO = new AccountDAO(getSession()); + localeDAO = new LocaleDAO(getSession()); + + service = seam + .use("requestDAO", requestDAO) + .use("languageRequestDAO", languageRequestDAO) + .use("event", requestUpdatedEvent) + .use("entityManager", getEm()) + .use("session", getSession()) + .ignoreNonResolvable() + .autowire(RequestServiceImpl.class); + } + + @Test + public void testCreateRequest() { + //admin user + HAccount requester = accountDAO.findById(1L); + //as locale + HLocale locale = localeDAO.findById(1L); + + boolean reqAsCoordinator = true; + boolean reqAsReviewer = false; + boolean reqAsTranslator = false; + + service.createLanguageRequest(requester, locale, reqAsCoordinator, + reqAsReviewer, reqAsTranslator); + + List result = + service.getPendingLanguageRequests(locale.getLocaleId()); + + assertThat(result).isNotEmpty().hasSize(1); + + LanguageRequest request = result.get(0); + assertThat(request.getCoordinator()).isEqualTo(reqAsCoordinator); + assertThat(request.getReviewer()).isEqualTo(reqAsReviewer); + assertThat(request.getTranslator()).isEqualTo(reqAsTranslator); + assertThat(request.getLocale().getLocaleId()) + .isEqualTo(locale.getLocaleId()); + assertThat(request.getRequest().getRequester()).isEqualTo(requester); + assertThat(request.getRequest().getState()).isEqualTo(null); + + assertThat(service.isLanguageRequestExist(requester, locale)).isTrue(); + } + + /** + * Use result from testCreateRequest + */ + @Test + public void testUpdateLanguageRequest() { + //admin user + HAccount requester = accountDAO.findById(1L); + //bn locale + HLocale locale = localeDAO.findById(2L); + + boolean reqAsCoordinator = true; + boolean reqAsReviewer = false; + boolean reqAsTranslator = false; + + LanguageRequest languageRequest = service.createLanguageRequest(requester, + locale, reqAsCoordinator, + reqAsReviewer, reqAsTranslator); + + String comment = "Accepted by admin"; + String entityId = languageRequest.getRequest().getEntityId(); + + service.updateLanguageRequest(languageRequest.getId(), requester, + RequestState.ACCEPTED, comment); + + verify(requestUpdatedEvent).fire(isA(RequestUpdatedEvent.class)); + + assertThat( + service.getPendingLanguageRequests(requester, locale.getLocaleId())) + .isNull(); + + List requests = service.getRequestByEntityId(entityId); + assertThat(requests).hasSize(2); + + for(Request request: requests) { + assertThat(request.getRequester()).isEqualTo(requester); + assertThat(request.getRequestType()).isEqualTo(RequestType.LOCALE); + } + + assertThat( + requests.get(0).getValidFrom() + .before(requests.get(1).getValidFrom())).isTrue(); + + assertThat(requests).extracting("state") + .contains(null, RequestState.ACCEPTED); + assertThat(requests).extracting("validTo").doesNotContainNull(); + } +}