responseQueue) {
86 | this.responseQueue = responseQueue;
87 | return this;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/services/http/UrlParameterParserTest.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.http;
2 |
3 | import com.contentful.tea.java.MainController;
4 | import com.contentful.tea.java.services.contentful.Contentful;
5 | import com.contentful.tea.java.services.settings.Settings;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.boot.test.mock.mockito.MockBean;
12 | import org.springframework.test.context.junit4.SpringRunner;
13 |
14 | import static org.assertj.core.api.Java6Assertions.assertThat;
15 | import static org.mockito.BDDMockito.given;
16 |
17 | @RunWith(SpringRunner.class)
18 | @SpringBootTest(classes = MainController.class)
19 | public class UrlParameterParserTest {
20 | @MockBean
21 | @SuppressWarnings("unused")
22 | private Settings settings;
23 |
24 | @MockBean
25 | @SuppressWarnings("unused")
26 | private Contentful contentful;
27 |
28 | @Autowired
29 | @SuppressWarnings("unused")
30 | private UrlParameterParser parser;
31 |
32 | @Test
33 | public void klingonLocaleGetsSavedAsUrlParameter() {
34 | given(settings.getLocale()).willReturn("tlh");
35 |
36 | final String subject = parser.appToUrlParameter();
37 |
38 | assertThat(subject).isEqualTo("?locale=tlh");
39 | }
40 |
41 | @Test
42 | public void twoParametersGetSavedAsUrl() {
43 | given(settings.getLocale()).willReturn("tlh");
44 | given(contentful.getApi()).willReturn("rest");
45 |
46 | final String subject = parser.appToUrlParameter();
47 |
48 | assertThat(subject).isEqualTo("?api=rest&locale=tlh");
49 | }
50 |
51 | @Test
52 | public void allParametersGetSavedAndNotMore() {
53 | given(settings.getLocale()).willReturn("tlh");
54 | given(settings.areEditorialFeaturesEnabled()).willReturn(true);
55 | given(contentful.getApi()).willReturn("rest");
56 | given(contentful.getDeliveryAccessToken()).willReturn("delivery");
57 | given(contentful.getPreviewAccessToken()).willReturn("preview");
58 | given(contentful.getSpaceId()).willReturn("space");
59 |
60 | final String subject = parser.appToUrlParameter();
61 |
62 | assertThat(subject).isEqualTo("?preview_token=preview&delivery_token=delivery&editorial_features=enabled&api=rest&locale=tlh&space_id=space");
63 | }
64 |
65 | @Test
66 | public void editorialFeaturesCanGetDisabled() {
67 | given(settings.areEditorialFeaturesEnabled()).willReturn(false);
68 |
69 | final String subject = parser.appToUrlParameter();
70 |
71 | assertThat(subject).isEqualTo("");
72 | }
73 |
74 | @Test
75 | public void editorialFeaturesCanGetEnabled() {
76 | given(settings.areEditorialFeaturesEnabled()).willReturn(true);
77 |
78 | final String subject = parser.appToUrlParameter();
79 |
80 | assertThat(subject).isEqualTo("?editorial_features=enabled");
81 | }
82 | }
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/MarkdownManipulatorTests.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java;
2 |
3 | import com.contentful.tea.java.markdown.MarkdownParser;
4 | import com.contentful.tea.java.utils.text.InjectText;
5 | import com.contentful.tea.java.utils.text.InjectTextBaseTests;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.test.context.junit4.SpringRunner;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 |
15 | @RunWith(SpringRunner.class)
16 | @SpringBootTest(classes = MainController.class)
17 | public class MarkdownManipulatorTests extends InjectTextBaseTests {
18 |
19 | @Autowired
20 | @SuppressWarnings("unused")
21 | private MarkdownParser markdownParser;
22 |
23 | @Test
24 | public void superSimpleTest() {
25 | assertThat(markdownParser.parse("foobar")).isEqualTo("foobar");
26 | assertThat(markdownParser.parse("_foobar_")).isEqualTo("foobar ");
27 | assertThat(markdownParser.parse("a\n\n\nb")).isEqualTo("a
\nb
\n");
28 | }
29 |
30 | @Test
31 | @InjectText("markdown/simple.md")
32 | public void testSimpleMarkdown() {
33 | assertThat(
34 | markdownParser.parse(injectedText)
35 | ).isEqualTo(
36 | "Switch to the language from English to German by going to the menu item Locale: U.S. English and selecting German."
37 | );
38 | }
39 |
40 | @Test
41 | @InjectText("markdown/complex.md")
42 | public void testComplexMarkdown() {
43 | assertThat(
44 | markdownParser.parse(injectedText)
45 | ).isEqualTo(
46 | "A simple Contentful setup consists of a client application reading content, such as this example app, and another application that is writing content, such as the Contentful web app. The client application is reading content by connecting to the Content Delivery API, and the Contentful Web app is writing content by connecting to the Content Mangement API:
\n" +
47 | "
\n" +
48 | "The Contentful web app is a single page application that Contentful provides to help with the most common tasks when managing content:
\n" +
49 | "\n" +
50 | "Provide an interface for editors to write content. \n" +
51 | "Provide an interface for developes to configure a space, model data, define roles and permissions, and set up webhook notifications. \n" +
52 | " \n" +
53 | "As mentioned, the Contentful web app is a client that uses the Content Management API. Therefore, you could replicate the functionality that the Contentful web app provides by making an API call. This is a powerful aspect of an API-first design because it helps you to connect Contentful to third-party systems.
\n"
54 | );
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/SecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java;
2 |
3 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | import java.io.IOException;
8 | import java.util.Objects;
9 | import java.util.stream.Collectors;
10 |
11 | import javax.servlet.Filter;
12 | import javax.servlet.FilterChain;
13 | import javax.servlet.FilterConfig;
14 | import javax.servlet.ServletException;
15 | import javax.servlet.ServletRequest;
16 | import javax.servlet.ServletResponse;
17 | import javax.servlet.http.HttpServletRequest;
18 | import javax.servlet.http.HttpServletResponse;
19 |
20 | import static java.lang.String.format;
21 | import static java.lang.String.join;
22 |
23 | @Configuration
24 | @EnableConfigurationProperties
25 | @SuppressWarnings("unused")
26 | public class SecurityConfig {
27 | static class HttpsEnforcer implements Filter {
28 |
29 | private FilterConfig filterConfig;
30 |
31 | public static final String X_FORWARDED_PROTO = "x-forwarded-proto";
32 |
33 | @Override
34 | public void init(FilterConfig filterConfig) throws ServletException {
35 | this.filterConfig = filterConfig;
36 | }
37 |
38 | @Override
39 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
40 | HttpServletRequest request = (HttpServletRequest) servletRequest;
41 | HttpServletResponse response = (HttpServletResponse) servletResponse;
42 |
43 | final String forwardedHeader = request.getHeader(X_FORWARDED_PROTO);
44 |
45 | if ("localhost".equals(request.getServerName())) {
46 | // ignore filters
47 | } else if (forwardedHeader != null && forwardedHeader.indexOf("https") != 0) {
48 | redirectToHttps(request, response);
49 | } else if (!request.isSecure()) {
50 | redirectToHttps(request, response);
51 | }
52 |
53 | if (!response.isCommitted()) {
54 | filterChain.doFilter(request, response);
55 | }
56 | }
57 |
58 | private void redirectToHttps(HttpServletRequest request, HttpServletResponse response) throws IOException {
59 | final String parameter = requestParameterToString(request);
60 | final String redirectUrl = format("https://%s/%s", request.getServerName(), parameter == null ? "" : "?" + parameter);
61 |
62 | response.sendRedirect(redirectUrl);
63 | }
64 |
65 | private String requestParameterToString(HttpServletRequest request) {
66 | return join("&",
67 | request
68 | .getParameterMap()
69 | .entrySet()
70 | .stream()
71 | .map(
72 | e -> e.getValue() != null && e.getValue().length > 0
73 | ? e.getKey() + "=" + e.getValue()[0]
74 | : null
75 | )
76 | .filter(Objects::nonNull)
77 | .collect(Collectors.toList()));
78 | }
79 |
80 | @Override
81 | public void destroy() {
82 | // nothing
83 | }
84 | }
85 |
86 | @Bean
87 | public Filter httpsEnforcerFilter() {
88 | return new HttpsEnforcer();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/localization/Keys.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.localization;
2 |
3 | public enum Keys {
4 | defaultTitle,
5 | whatIsThisApp,
6 | metaDescription,
7 | metaTwitterCard,
8 | metaImageAlt,
9 | metaImageDescription,
10 | viewOnGithub,
11 | apiSwitcherHelp,
12 | contentDeliveryApiLabel,
13 | contentDeliveryApiHelp,
14 | contentPreviewApiLabel,
15 | contentPreviewApiHelp,
16 | locale,
17 | localeQuestion,
18 | settingsLabel,
19 | logoAlt,
20 | homeLabel,
21 | coursesLabel,
22 | lessonsLabel,
23 | footerDisclaimer,
24 | imprintLabel,
25 | contactUsLabel,
26 | modalTitle,
27 | modalTitleDotnet,
28 | modalTitleRuby,
29 | modalTitlePhp,
30 | modalTitlePython,
31 | modalTitleSwift,
32 | modalTitleAndroid,
33 | modalTitleJava,
34 | modalIntro,
35 | modalIntroDotnet,
36 | modalIntroRuby,
37 | modalIntroPhp,
38 | modalIntroPython,
39 | modalIntroSwift,
40 | modalIntroAndroid,
41 | modalIntroJava,
42 | modalSpaceIntro,
43 | modalPlatforms,
44 | modalSpaceLinkLabel,
45 | modalCTALabel,
46 | editorialFeaturesHint,
47 | draftLabel,
48 | pendingChangesLabel,
49 | lessonModuleErrorTitle,
50 | lessonModuleErrorBody,
51 | nextLessonLabel,
52 | imageErrorTitle,
53 | viewCourseLabel,
54 | categoriesWelcomeLabel,
55 | sitemapWelcomeLabel,
56 | tableOfContentsLabel,
57 | courseOverviewLabel,
58 | overviewLabel,
59 | durationLabel,
60 | minutesLabel,
61 | skillLevelLabel,
62 | startCourseLabel,
63 | categoriesLabel,
64 | allCoursesLabel,
65 | companyLabel,
66 | officeLabel,
67 | germanyLabel,
68 | registrationCourtLabel,
69 | managingDirectorLabel,
70 | vatNumberLabel,
71 | settingsIntroLabel,
72 | changesSavedLabel,
73 | errorOccurredTitleLabel,
74 | errorOccurredMessageLabel,
75 | connectedToSpaceLabel,
76 | spaceIdLabel,
77 | spaceIdHelpText,
78 | accessTokenLabel,
79 | cdaAccessTokenLabel,
80 | cpaAccessTokenLabel,
81 | contentDeliveryApiHelpText,
82 | contentPreviewApiHelpText,
83 | enableEditorialFeaturesLabel,
84 | enableEditorialFeaturesHelpText,
85 | saveSettingsButtonLabel,
86 | fieldIsRequiredLabel,
87 | deliveryKeyInvalidLabel,
88 | spaceOrTokenInvalid,
89 | previewKeyInvalidLabel,
90 | beginnerLabel,
91 | intermediateLabel,
92 | advancedLabel,
93 | editInTheWebAppLabel,
94 | currentLocaleLabel,
95 | hostedLabel,
96 | comingSoonLabel,
97 | credentialSourceLabel,
98 | readMoreLabel,
99 | credentialsLocationLabel,
100 | overwriteCredentialsLabel,
101 | copyLinkLabel,
102 | resetCredentialsLabel,
103 | resetAboveLabel,
104 | closeLabel,
105 | overrideConfigLabel,
106 | loadedFromLocalFileLabel,
107 | usingServerCredentialsLabel,
108 | usingSessionCredentialsLabel,
109 | applicationCredentialsLabel,
110 | noContentLabel,
111 | errorHighlightedCourse,
112 | somethingWentWrongLabel,
113 | errorMessage404Route,
114 | errorMessage404Lesson,
115 | errorMessage404Course,
116 | errorMessage404Category,
117 | hintsLabel,
118 | notFoundErrorHint,
119 | contentModelChangedErrorHint,
120 | draftOrPublishedErrorHint,
121 | localeContentErrorHint,
122 | verifyCredentialsErrorHint,
123 | stackTraceErrorHint,
124 | errorLabel,
125 | stackTraceLabel
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/http/SessionParser.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.http;
2 |
3 | import com.contentful.tea.java.services.contentful.Contentful;
4 | import com.contentful.tea.java.services.settings.Settings;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Component;
8 |
9 | import java.util.Enumeration;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import javax.servlet.http.HttpSession;
14 |
15 | import static com.contentful.tea.java.services.http.Constants.EDITORIAL_FEATURES_DISABLED;
16 | import static com.contentful.tea.java.services.http.Constants.EDITORIAL_FEATURES_ENABLED;
17 |
18 | @Component
19 | public class SessionParser {
20 | private static final int TIME_48_HOURS = 48 * 60 * 60;
21 | @Autowired
22 | @SuppressWarnings("unused")
23 | private Contentful contentful;
24 |
25 | @Autowired
26 | @SuppressWarnings("unused")
27 | private Settings settings;
28 |
29 | private final Map manipulatorsByNameMap;
30 |
31 | public SessionParser() {
32 | manipulatorsByNameMap = new HashMap<>();
33 | manipulatorsByNameMap.put(Constants.NAME_SPACE_ID, new Manipulator() {
34 | @Override public String get() {
35 | return contentful.getSpaceId();
36 | }
37 |
38 | @Override public void set(String value) {
39 | contentful.setSpaceId(value);
40 | }
41 | });
42 | manipulatorsByNameMap.put(Constants.NAME_DELIVERY_TOKEN, new Manipulator() {
43 | @Override public String get() {
44 | return contentful.getDeliveryAccessToken();
45 | }
46 |
47 | @Override public void set(String value) {
48 | contentful.setDeliveryAccessToken(value);
49 | }
50 | });
51 | manipulatorsByNameMap.put(Constants.NAME_PREVIEW_TOKEN, new Manipulator() {
52 | @Override public String get() {
53 | return contentful.getPreviewAccessToken();
54 | }
55 |
56 | @Override public void set(String value) {
57 | contentful.setPreviewAccessToken(value);
58 | }
59 | });
60 | manipulatorsByNameMap.put(Constants.NAME_EDITORIAL_FEATURES, new Manipulator() {
61 | @Override public String get() {
62 | return settings.areEditorialFeaturesEnabled() ? EDITORIAL_FEATURES_ENABLED : EDITORIAL_FEATURES_DISABLED;
63 | }
64 |
65 | @Override public void set(String value) {
66 | settings.setEditorialFeaturesEnabled(value != null && value.toLowerCase().equals(EDITORIAL_FEATURES_ENABLED));
67 | }
68 | });
69 | }
70 |
71 | public void loadFromSession(HttpSession session) {
72 | final Enumeration names = session.getAttributeNames();
73 | for (; names.hasMoreElements(); ) {
74 | final String name = names.nextElement();
75 | final Manipulator manipulator = manipulatorsByNameMap.get(name);
76 |
77 | if (manipulator != null) {
78 | final Object value = session.getAttribute(name);
79 | manipulator.set(value);
80 | }
81 | }
82 |
83 | session.setMaxInactiveInterval(TIME_48_HOURS);
84 | }
85 |
86 | public void saveToSession(HttpSession session) {
87 | manipulatorsByNameMap
88 | .keySet()
89 | .forEach(name -> session.setAttribute(name, manipulatorsByNameMap.get(name).get()));
90 | }
91 |
92 | interface Manipulator {
93 | T get();
94 |
95 | void set(T value);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/services/http/SessionParserTest.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.http;
2 |
3 | import com.contentful.tea.java.MainController;
4 | import com.contentful.tea.java.services.contentful.Contentful;
5 | import com.contentful.tea.java.services.settings.Settings;
6 |
7 | import org.junit.After;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.mock.web.MockHttpSession;
13 | import org.springframework.test.context.junit4.SpringRunner;
14 |
15 | import java.util.Enumeration;
16 | import java.util.HashMap;
17 | import java.util.Map;
18 |
19 | import javax.servlet.http.HttpSession;
20 |
21 | import static com.contentful.tea.java.services.http.Constants.NAME_DELIVERY_TOKEN;
22 | import static com.contentful.tea.java.services.http.Constants.NAME_EDITORIAL_FEATURES;
23 | import static com.contentful.tea.java.services.http.Constants.NAME_PREVIEW_TOKEN;
24 | import static com.contentful.tea.java.services.http.Constants.NAME_SPACE_ID;
25 | import static org.assertj.core.api.Java6Assertions.assertThat;
26 |
27 | @RunWith(SpringRunner.class)
28 | @SpringBootTest(classes = MainController.class)
29 | public class SessionParserTest {
30 |
31 | @Autowired
32 | @SuppressWarnings("unused")
33 | private Contentful contentful;
34 |
35 | @Autowired
36 | @SuppressWarnings("unused")
37 | private Settings settings;
38 |
39 | @Autowired
40 | @SuppressWarnings("unused")
41 | private SessionParser parser;
42 |
43 | @After
44 | public void teardown() {
45 | contentful.reset();
46 | settings.reset();
47 | }
48 |
49 | @Test
50 | public void parserLoadsSession() {
51 | final HttpSession session = new MockHttpSession();
52 |
53 | session.setAttribute(NAME_SPACE_ID, "spaceId");
54 | session.setAttribute(NAME_DELIVERY_TOKEN, "cdaToken");
55 | session.setAttribute(NAME_PREVIEW_TOKEN, "cpaToken");
56 |
57 | parser.loadFromSession(session);
58 |
59 | assertThat(contentful.getSpaceId()).isEqualTo("spaceId");
60 | assertThat(contentful.getDeliveryAccessToken()).isEqualTo("cdaToken");
61 | assertThat(contentful.getPreviewAccessToken()).isEqualTo("cpaToken");
62 | }
63 |
64 | @Test
65 | public void parserSavesSession() {
66 | contentful
67 | .setSpaceId("spaceId")
68 | .setDeliveryAccessToken("cdaToken")
69 | .setPreviewAccessToken("cpaToken");
70 |
71 | final HttpSession session = new MockHttpSession();
72 | parser.saveToSession(session);
73 |
74 | assertThat(session.getAttributeNames()).isNotNull();
75 | Map attributes = extractAttributesIntoMap(session);
76 |
77 | final String[] names = attributes.keySet().toArray(new String[attributes.size()]);
78 | assertThat(names)
79 | .containsExactlyInAnyOrder(NAME_DELIVERY_TOKEN, NAME_PREVIEW_TOKEN, NAME_SPACE_ID, NAME_EDITORIAL_FEATURES);
80 |
81 | final Object[] values = attributes.values().toArray();
82 | assertThat(values)
83 | .containsExactlyInAnyOrder("spaceId", "cdaToken", "cpaToken", "disabled");
84 | }
85 |
86 | private Map extractAttributesIntoMap(HttpSession session) {
87 | final Map map = new HashMap<>();
88 |
89 | final Enumeration names = session.getAttributeNames();
90 | for (; names.hasMoreElements(); ) {
91 | final String name = names.nextElement();
92 | final Object value = session.getAttribute(name);
93 | map.put(name, value);
94 | }
95 |
96 | return map;
97 | }
98 | }
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/settings/Settings.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.settings;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | import java.util.Objects;
6 |
7 | @Component
8 | public class Settings {
9 |
10 | private static final String DEFAULT_LOCALE = "en-US";
11 |
12 | private String queryString;
13 | private String baseUrl;
14 | private String path;
15 | private String locale = DEFAULT_LOCALE;
16 |
17 | private boolean editorialFeaturesEnabled;
18 |
19 | public Settings() {
20 | reset();
21 | }
22 |
23 | public String getLocale() {
24 | return locale;
25 | }
26 |
27 | public Settings setLocale(String locale) {
28 | this.locale = locale;
29 | return this;
30 | }
31 |
32 | public String getQueryString() {
33 | return queryString;
34 | }
35 |
36 | public Settings setQueryString(String queryString) {
37 | this.queryString = queryString;
38 | return this;
39 | }
40 |
41 | public String getPath() {
42 | return path;
43 | }
44 |
45 | public Settings setPath(String path) {
46 | this.path = path;
47 | return this;
48 | }
49 |
50 | public boolean areEditorialFeaturesEnabled() {
51 | return editorialFeaturesEnabled;
52 | }
53 |
54 | public Settings setEditorialFeaturesEnabled(boolean editorialFeaturesEnabled) {
55 | this.editorialFeaturesEnabled = editorialFeaturesEnabled;
56 | return this;
57 | }
58 |
59 | public String getBaseUrl() {
60 | return baseUrl;
61 | }
62 |
63 | public Settings setBaseUrl(String baseUrl) {
64 | this.baseUrl = baseUrl;
65 | return this;
66 | }
67 |
68 | @Override public String toString() {
69 | return "Settings { "
70 | + "locale = " + getLocale() + ", "
71 | + "baseUrl = " + getBaseUrl() + ", "
72 | + "path = " + getPath() + ", "
73 | + "queryString = " + getQueryString() + ", "
74 | + "editorialFeaturesEnabled = " + areEditorialFeaturesEnabled() + " "
75 | + "}";
76 | }
77 |
78 | @Override public boolean equals(Object o) {
79 | if (this == o) return true;
80 | if (!(o instanceof Settings)) return false;
81 | final Settings settings = (Settings) o;
82 | return Objects.equals(getQueryString(), settings.getQueryString()) &&
83 | Objects.equals(getLocale(), settings.getLocale()) &&
84 | Objects.equals(areEditorialFeaturesEnabled(), settings.areEditorialFeaturesEnabled());
85 | }
86 |
87 | @Override public int hashCode() {
88 | return Objects.hash(getBaseUrl(), getQueryString(), getPath(), getLocale(), areEditorialFeaturesEnabled());
89 | }
90 |
91 | public Settings save() {
92 | return
93 | new Settings()
94 | .setEditorialFeaturesEnabled(areEditorialFeaturesEnabled())
95 | .setBaseUrl(getBaseUrl())
96 | .setLocale(getLocale())
97 | .setPath(getPath())
98 | .setQueryString(getQueryString())
99 | ;
100 | }
101 |
102 | public Settings load(Settings lastSettings) {
103 | setEditorialFeaturesEnabled(lastSettings.areEditorialFeaturesEnabled());
104 | setLocale(lastSettings.getLocale());
105 | setBaseUrl(lastSettings.getBaseUrl());
106 | setPath(lastSettings.getPath());
107 | setQueryString(lastSettings.getQueryString());
108 | return this;
109 | }
110 |
111 | public Settings reset() {
112 | setEditorialFeaturesEnabled(false);
113 | setLocale(DEFAULT_LOCALE);
114 | setBaseUrl(null);
115 | setPath(null);
116 | setQueryString(null);
117 |
118 | return this;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/services/http/UrlParserTest.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.http;
2 |
3 | import com.contentful.tea.java.MainController;
4 | import com.contentful.tea.java.services.contentful.Contentful;
5 | import com.contentful.tea.java.services.settings.Settings;
6 |
7 | import org.junit.After;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.test.context.junit4.SpringRunner;
13 |
14 | import java.util.Collections;
15 | import java.util.HashMap;
16 | import java.util.Map;
17 |
18 | import static com.contentful.tea.java.services.http.Constants.NAME_API;
19 | import static com.contentful.tea.java.services.http.Constants.NAME_DELIVERY_TOKEN;
20 | import static com.contentful.tea.java.services.http.Constants.NAME_EDITORIAL_FEATURES;
21 | import static com.contentful.tea.java.services.http.Constants.NAME_LOCALE;
22 | import static com.contentful.tea.java.services.http.Constants.NAME_PREVIEW_TOKEN;
23 | import static com.contentful.tea.java.services.http.Constants.NAME_SPACE_ID;
24 | import static java.util.Collections.singletonMap;
25 | import static org.assertj.core.api.Java6Assertions.assertThat;
26 |
27 | @RunWith(SpringRunner.class)
28 | @SpringBootTest(classes = MainController.class)
29 | public class UrlParserTest {
30 |
31 | @Autowired
32 | @SuppressWarnings("unused")
33 | private Contentful contentful;
34 |
35 | @Autowired
36 | @SuppressWarnings("unused")
37 | private Settings settings;
38 |
39 | @Autowired
40 | @SuppressWarnings("unused")
41 | private UrlParameterParser parser;
42 |
43 | @After
44 | public void tearDown() {
45 | contentful.reset();
46 | settings.reset();
47 | }
48 |
49 | @Test
50 | public void parsingNoParameterDoesNotChangeSettings() {
51 | final String before = contentful.toString();
52 |
53 | parser.urlParameterToApp(Collections.emptyMap());
54 |
55 | final String after = contentful.toString();
56 | assertThat(before).isEqualTo(after);
57 | }
58 |
59 | @Test
60 | public void parsingNullParameterDoesNotChangeSettings() {
61 | final String before = contentful.toString();
62 |
63 | parser.urlParameterToApp(null);
64 |
65 | final String after = contentful.toString();
66 | assertThat(before).isEqualTo(after);
67 | }
68 |
69 | @Test
70 | public void tokenInUrlChangesTokenInSettings() {
71 | parser.urlParameterToApp(singletonMap(NAME_DELIVERY_TOKEN, new String[]{"cda_token"}));
72 |
73 | final String after = contentful.getDeliveryAccessToken();
74 | assertThat(after).isEqualTo("cda_token");
75 | }
76 |
77 | @Test
78 | public void allParameterCanGetParsed() {
79 | final Map map = new HashMap<>();
80 | map.put(NAME_API, new String[]{"cpa"});
81 | map.put(NAME_SPACE_ID, new String[]{"TEST_NAME_SPACE_ID"});
82 | map.put(NAME_LOCALE, new String[]{"TEST_NAME_LOCALE"});
83 | map.put(NAME_DELIVERY_TOKEN, new String[]{"TEST_NAME_DELIVERY_TOKEN"});
84 | map.put(NAME_PREVIEW_TOKEN, new String[]{"TEST_NAME_PREVIEW_TOKEN"});
85 | map.put(NAME_EDITORIAL_FEATURES, new String[]{"enabled"});
86 |
87 | parser.urlParameterToApp(map);
88 |
89 | assertThat(contentful.getApi()).isEqualTo("cpa");
90 | assertThat(contentful.getSpaceId()).isEqualTo("TEST_NAME_SPACE_ID");
91 | assertThat(contentful.getDeliveryAccessToken()).isEqualTo("TEST_NAME_DELIVERY_TOKEN");
92 | assertThat(contentful.getPreviewAccessToken()).isEqualTo("TEST_NAME_PREVIEW_TOKEN");
93 | assertThat(settings.getLocale()).isEqualTo("TEST_NAME_LOCALE");
94 | assertThat(settings.areEditorialFeaturesEnabled()).isEqualTo(true);
95 | }
96 | }
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/modelconverter/EntryToLesson.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.modelconverter;
2 |
3 | import com.contentful.java.cda.CDAAsset;
4 | import com.contentful.java.cda.CDAEntry;
5 | import com.contentful.tea.java.models.courses.lessons.LessonParameter;
6 | import com.contentful.tea.java.models.courses.lessons.modules.CodeModule;
7 | import com.contentful.tea.java.models.courses.lessons.modules.CopyModule;
8 | import com.contentful.tea.java.models.courses.lessons.modules.ImageModule;
9 | import com.contentful.tea.java.models.courses.lessons.modules.Module;
10 | import com.contentful.tea.java.services.localization.Keys;
11 | import com.contentful.tea.java.services.modelenhancers.EditorialFeaturesEnhancer;
12 | import com.contentful.tea.java.services.settings.Settings;
13 |
14 | import org.springframework.beans.factory.annotation.Autowired;
15 | import org.springframework.stereotype.Component;
16 |
17 | import java.util.List;
18 |
19 | import static com.contentful.java.cda.image.ImageOption.https;
20 |
21 | @Component
22 | public class EntryToLesson extends ContentfulModelToMappableTypeConverter {
23 |
24 | @Autowired
25 | @SuppressWarnings("unused")
26 | private Settings settings;
27 |
28 | @Autowired
29 | @SuppressWarnings("unused")
30 | private EditorialFeaturesEnhancer enhancer;
31 |
32 | @Override
33 | public LessonParameter convert(CDAEntry cdaLesson, int editorialFeaturesDepth) {
34 | final LessonParameter result = new LessonParameter()
35 | .setSlug(cdaLesson.getField("slug"))
36 | .setTitle(cdaLesson.getField("title"));
37 |
38 | final List cdaModules = cdaLesson.getField("modules");
39 | if (cdaModules != null) {
40 | for (final CDAEntry cdaModule : cdaModules) {
41 | final Module module = createModule(cdaModule);
42 | if (module != null) {
43 | result.addModule(module);
44 | }
45 |
46 | if (editorialFeaturesDepth > 0) {
47 | if (enhancer.isPending(cdaModule)) {
48 | result.getBase().getMeta().setPendingChanges(true);
49 | }
50 | if (enhancer.isDraft(cdaModule)) {
51 | result.getBase().getMeta().setDraft(true);
52 | }
53 | }
54 | }
55 | }
56 |
57 | if (editorialFeaturesDepth > 0) {
58 | enhancer.enhance(cdaLesson, result.getBase());
59 | }
60 |
61 | return result;
62 | }
63 |
64 | private Module createModule(CDAEntry cdaModule) {
65 | final String title = m(cdaModule.getField("title"));
66 | switch (cdaModule.contentType().id()) {
67 | case "lessonCopy":
68 | return new CopyModule()
69 | .setTitle(title)
70 | .setCopy(m(cdaModule.getField("copy")))
71 | ;
72 | case "lessonImage":
73 | return new ImageModule()
74 | .setTitle(title)
75 | .setCaption(m(cdaModule.getField("caption")))
76 | .setMissingImageLabel(t(Keys.imageErrorTitle))
77 | .setImageUrl(((CDAAsset) cdaModule.getField("image")).urlForImageWith(https()))
78 | ;
79 | case "lessonCodeSnippets":
80 | return new CodeModule()
81 | .setTitle(title)
82 | .setCurl(cdaModule.getField("curl"))
83 | .setDotNet(cdaModule.getField("dotNet"))
84 | .setJava(cdaModule.getField("java"))
85 | .setJavaAndroid(cdaModule.getField("javaAndroid"))
86 | .setJavascript(cdaModule.getField("javascript"))
87 | .setPhp(cdaModule.getField("php"))
88 | .setPython(cdaModule.getField("python"))
89 | .setRuby(cdaModule.getField("ruby"))
90 | .setSwift(cdaModule.getField("swift"))
91 | ;
92 | default:
93 | return null;
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/models/imprint/ImprintParameter.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.models.imprint;
2 |
3 | import com.contentful.tea.java.models.base.BaseParameter;
4 | import com.contentful.tea.java.models.mappable.MappableType;
5 |
6 | import java.util.Objects;
7 |
8 | public class ImprintParameter extends MappableType {
9 | private BaseParameter base = new BaseParameter();
10 |
11 | private String companyLabel;
12 | private String officeLabel;
13 | private String germanyLabel;
14 | private String registrationCourtLabel;
15 | private String managingDirectorLabel;
16 | private String vatNumberLabel;
17 |
18 | public BaseParameter getBase() {
19 | return base;
20 | }
21 |
22 | public String getCompanyLabel() {
23 | return companyLabel;
24 | }
25 |
26 | public ImprintParameter setCompanyLabel(String companyLabel) {
27 | this.companyLabel = companyLabel;
28 | return this;
29 | }
30 |
31 | public String getOfficeLabel() {
32 | return officeLabel;
33 | }
34 |
35 | public ImprintParameter setOfficeLabel(String officeLabel) {
36 | this.officeLabel = officeLabel;
37 | return this;
38 | }
39 |
40 | public String getGermanyLabel() {
41 | return germanyLabel;
42 | }
43 |
44 | public ImprintParameter setGermanyLabel(String germanyLabel) {
45 | this.germanyLabel = germanyLabel;
46 | return this;
47 | }
48 |
49 | public String getRegistrationCourtLabel() {
50 | return registrationCourtLabel;
51 | }
52 |
53 | public ImprintParameter setRegistrationCourtLabel(String registrationCourtLabel) {
54 | this.registrationCourtLabel = registrationCourtLabel;
55 | return this;
56 | }
57 |
58 | public String getManagingDirectorLabel() {
59 | return managingDirectorLabel;
60 | }
61 |
62 | public ImprintParameter setManagingDirectorLabel(String managingDirectorLabel) {
63 | this.managingDirectorLabel = managingDirectorLabel;
64 | return this;
65 | }
66 |
67 | public String getVatNumberLabel() {
68 | return vatNumberLabel;
69 | }
70 |
71 | public ImprintParameter setVatNumberLabel(String vatNumberLabel) {
72 | this.vatNumberLabel = vatNumberLabel;
73 | return this;
74 | }
75 |
76 | @Override public boolean equals(Object o) {
77 | if (this == o) return true;
78 | if (!(o instanceof ImprintParameter)) return false;
79 | final ImprintParameter that = (ImprintParameter) o;
80 | return Objects.equals(base, that.base) &&
81 | Objects.equals(getCompanyLabel(), that.getCompanyLabel()) &&
82 | Objects.equals(getOfficeLabel(), that.getOfficeLabel()) &&
83 | Objects.equals(getGermanyLabel(), that.getGermanyLabel()) &&
84 | Objects.equals(getRegistrationCourtLabel(), that.getRegistrationCourtLabel()) &&
85 | Objects.equals(getManagingDirectorLabel(), that.getManagingDirectorLabel()) &&
86 | Objects.equals(getVatNumberLabel(), that.getVatNumberLabel());
87 | }
88 |
89 | @Override public int hashCode() {
90 | return Objects.hash(base, getCompanyLabel(), getOfficeLabel(), getGermanyLabel(), getRegistrationCourtLabel(), getManagingDirectorLabel(), getVatNumberLabel());
91 | }
92 |
93 | /**
94 | * @return a human readable string, representing the object.
95 | */
96 | @Override public String toString() {
97 | return "ImprintParameter { " + super.toString() + " "
98 | + "companyLabel = " + getCompanyLabel() + ", "
99 | + "germanyLabel = " + getGermanyLabel() + ", "
100 | + "managingDirectorLabel = " + getManagingDirectorLabel() + ", "
101 | + "officeLabel = " + getOfficeLabel() + ", "
102 | + "registrationCourtLabel = " + getRegistrationCourtLabel() + ", "
103 | + "vatNumberLabel = " + getVatNumberLabel() + " "
104 | + "}";
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/modelconverter/ExceptionToErrorParameter.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.modelconverter;
2 |
3 | import com.contentful.java.cda.CDAHttpException;
4 | import com.contentful.tea.java.models.base.BaseParameter;
5 | import com.contentful.tea.java.models.base.Locale;
6 | import com.contentful.tea.java.models.errors.ErrorParameter;
7 | import com.contentful.tea.java.models.exceptions.TeaException;
8 | import com.contentful.tea.java.services.StaticContentSetter;
9 | import com.contentful.tea.java.services.contentful.Contentful;
10 | import com.contentful.tea.java.services.localization.Keys;
11 | import com.contentful.tea.java.services.localization.Localizer;
12 |
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.core.convert.converter.Converter;
15 | import org.springframework.stereotype.Component;
16 |
17 | import java.util.Collections;
18 | import java.util.List;
19 | import java.util.Objects;
20 | import java.util.function.Predicate;
21 |
22 | import static java.util.stream.Collectors.toList;
23 | import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace;
24 |
25 | @Component
26 | public class ExceptionToErrorParameter implements Converter {
27 |
28 | @Autowired
29 | @SuppressWarnings("unused")
30 | StaticContentSetter staticContentSetter;
31 |
32 | @Autowired
33 | @SuppressWarnings("unused")
34 | Localizer localizer;
35 |
36 | @Autowired
37 | @SuppressWarnings("unused")
38 | Contentful contentful;
39 |
40 | @Override
41 | public ErrorParameter convert(Throwable source) {
42 | final ErrorParameter errorParameter = new ErrorParameter();
43 | final BaseParameter base = errorParameter.getBase();
44 | staticContentSetter.applyErrorContent(base);
45 | base.getLocales()
46 | .setCurrentLocaleName("U.S. English")
47 | .setCurrentLocaleCode("en-US")
48 | .addLocale(
49 | new Locale()
50 | .setCode("en-US")
51 | .setName("U.S. English")
52 | .setCssClass(Locale.CSS_CLASS_ACTIVE),
53 | new Locale()
54 | .setCode("de-DE")
55 | .setName("Germany (Germany)")
56 | .setCssClass("")
57 | )
58 | ;
59 |
60 | base.getMeta().setTitle(t(Keys.errorOccurredTitleLabel));
61 |
62 | return errorParameter
63 | .setHints(hintKeysToHints(source))
64 | .setResponseDataLabel(t(Keys.errorLabel))
65 | .setSomethingWentWrongLabel(t(Keys.somethingWentWrongLabel))
66 | .setResponseData(getResponseData(source))
67 | .setStatus(404)
68 | .setTryLabel(t(Keys.hintsLabel))
69 | .setStackTraceLabel(t(Keys.stackTraceLabel))
70 | .setStack(getStackTrace(source))
71 | .setUseCustomCredentials(contentful.isUsingCustomCredentials())
72 | .setResetCredentialsLabel(t(Keys.resetCredentialsLabel))
73 | ;
74 | }
75 |
76 | private List hintKeysToHints(Throwable source) {
77 | final List keys = source instanceof TeaException ? ((TeaException) source).createHints() : Collections.singletonList(Keys.notFoundErrorHint);
78 | return keys
79 | .stream()
80 | .filter(Objects::nonNull)
81 | .map(this::t)
82 | .filter(not(String::isEmpty))
83 | .collect(toList());
84 | }
85 |
86 | private static Predicate not(Predicate t) {
87 | return t.negate();
88 | }
89 |
90 | private String getResponseData(Throwable source) {
91 | final Throwable cause = source.getCause();
92 | return cause instanceof CDAHttpException ? cause.toString() : null;
93 | }
94 |
95 | public String t(Keys key) {
96 | return localizer.localize(key);
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/models/courses/lessons/modules/CodeModule.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.models.courses.lessons.modules;
2 |
3 | import java.util.Objects;
4 |
5 | public class CodeModule extends Module {
6 | private String curl;
7 | private String dotNet;
8 | private String javascript;
9 | private String java;
10 | private String javaAndroid;
11 | private String php;
12 | private String python;
13 | private String ruby;
14 | private String swift;
15 |
16 | public CodeModule() {
17 | super("code");
18 | }
19 |
20 | public String getCurl() {
21 | return curl;
22 | }
23 |
24 | public CodeModule setCurl(String curl) {
25 | this.curl = curl;
26 | return this;
27 | }
28 |
29 | public String getDotNet() {
30 | return dotNet;
31 | }
32 |
33 | public CodeModule setDotNet(String dotNet) {
34 | this.dotNet = dotNet;
35 | return this;
36 | }
37 |
38 | public String getJavascript() {
39 | return javascript;
40 | }
41 |
42 | public CodeModule setJavascript(String javascript) {
43 | this.javascript = javascript;
44 | return this;
45 | }
46 |
47 | public String getJava() {
48 | return java;
49 | }
50 |
51 | public CodeModule setJava(String java) {
52 | this.java = java;
53 | return this;
54 | }
55 |
56 | public String getJavaAndroid() {
57 | return javaAndroid;
58 | }
59 |
60 | public CodeModule setJavaAndroid(String javaAndroid) {
61 | this.javaAndroid = javaAndroid;
62 | return this;
63 | }
64 |
65 | public String getPhp() {
66 | return php;
67 | }
68 |
69 | public CodeModule setPhp(String php) {
70 | this.php = php;
71 | return this;
72 | }
73 |
74 | public String getPython() {
75 | return python;
76 | }
77 |
78 | public CodeModule setPython(String python) {
79 | this.python = python;
80 | return this;
81 | }
82 |
83 | public String getRuby() {
84 | return ruby;
85 | }
86 |
87 | public CodeModule setRuby(String ruby) {
88 | this.ruby = ruby;
89 | return this;
90 | }
91 |
92 | public String getSwift() {
93 | return swift;
94 | }
95 |
96 | public CodeModule setSwift(String swift) {
97 | this.swift = swift;
98 | return this;
99 | }
100 |
101 | @Override public boolean equals(Object o) {
102 | if (this == o) return true;
103 | if (!(o instanceof CodeModule)) return false;
104 | if (!super.equals(o)) return false;
105 | final CodeModule that = (CodeModule) o;
106 | return Objects.equals(getCurl(), that.getCurl()) &&
107 | Objects.equals(getDotNet(), that.getDotNet()) &&
108 | Objects.equals(getJavascript(), that.getJavascript()) &&
109 | Objects.equals(getJava(), that.getJava()) &&
110 | Objects.equals(getJavaAndroid(), that.getJavaAndroid()) &&
111 | Objects.equals(getPhp(), that.getPhp()) &&
112 | Objects.equals(getPython(), that.getPython()) &&
113 | Objects.equals(getRuby(), that.getRuby()) &&
114 | Objects.equals(getSwift(), that.getSwift());
115 | }
116 |
117 | @Override public int hashCode() {
118 | return Objects.hash(super.hashCode(), getCurl(), getDotNet(), getJavascript(), getJava(), getJavaAndroid(), getPhp(), getPython(), getRuby(), getSwift());
119 | }
120 |
121 | @Override public String toString() {
122 | return "CodeModule { " + super.toString() + " "
123 | + "curl = " + getCurl() + ", "
124 | + "dotNet = " + getDotNet() + ", "
125 | + "java = " + getJava() + ", "
126 | + "javaAndroid = " + getJavaAndroid() + ", "
127 | + "javascript = " + getJavascript() + ", "
128 | + "php = " + getPhp() + ", "
129 | + "python = " + getPython() + ", "
130 | + "ruby = " + getRuby() + ", "
131 | + "swift = " + getSwift() + " "
132 | + "}";
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/MappableTypeTests.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java;
2 |
3 | import com.contentful.tea.java.models.base.BaseParameter;
4 | import com.contentful.tea.java.models.mappable.MappableType;
5 |
6 | import org.junit.Test;
7 |
8 | import java.util.Arrays;
9 | import java.util.LinkedHashMap;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 | import static org.assertj.core.api.Assertions.entry;
15 |
16 | public class MappableTypeTests {
17 | @Test
18 | public void simpleMappable() {
19 | Map nestedMap = new LinkedHashMap<>();
20 | nestedMap.put("x", 12);
21 | nestedMap.put("y", 24.0);
22 |
23 | assertThat(
24 | new MappableType() {
25 | private int i = 42;
26 | private String s = "string";
27 | private MappableType nested = new MappableType() {
28 | private int x = 12;
29 | private double y = 24.0;
30 | };
31 | }.toMap()
32 | )
33 | .containsExactly(
34 | entry("i", 42),
35 | entry("s", "string"),
36 | entry("nested", nestedMap)
37 | );
38 | }
39 |
40 | @Test
41 | public void mappableWithArrayElementsTest() {
42 | final Map actual = new MappableType() {
43 | private String[] array = new String[]{"a", "b", "c"};
44 | }.toMap();
45 |
46 | assertThat(actual).containsOnlyKeys("array");
47 | final String[] array = (String[]) actual.get("array");
48 | assertThat(array.length).isEqualTo(3);
49 | assertThat(array[0]).isEqualTo("a");
50 | assertThat(array[1]).isEqualTo("b");
51 | assertThat(array[2]).isEqualTo("c");
52 | }
53 |
54 | @Test
55 | public void mappableWithArrayContainingMappableElementsTest() {
56 | final Map actual = new MappableType() {
57 | private final MappableType[] array = new MappableType[]{
58 | new MappableType() {
59 | int x = 12;
60 | },
61 | new MappableType() {
62 | int y = 13;
63 | },
64 | new MappableType() {
65 | int z = 14;
66 | }
67 | };
68 | }.toMap();
69 |
70 | assertThat(actual).containsKey("array");
71 |
72 | final Object arrayObject = actual.get("array");
73 | assertThat(arrayObject).isInstanceOf(Map[].class);
74 |
75 | final Map[] array = (Map[]) arrayObject;
76 | assertThat(array[0].get("x")).isEqualTo(12);
77 | assertThat(array[1].get("y")).isEqualTo(13);
78 | assertThat(array[2].get("z")).isEqualTo(14);
79 | }
80 |
81 | @Test
82 | public void mappableWithListContainingMappableElementsTest() {
83 | final Map actual = new MappableType() {
84 | private final List list = Arrays.asList(
85 | new MappableType() {
86 | int x = 12;
87 | },
88 | new MappableType() {
89 | int y = 13;
90 | },
91 | new MappableType() {
92 | int z = 14;
93 | }
94 | );
95 | }.toMap();
96 |
97 |
98 | assertThat(actual).containsKey("list");
99 |
100 | final Object listObject = actual.get("list");
101 | assertThat(listObject).isInstanceOf(List.class);
102 |
103 | final List> list = (List>) listObject;
104 | assertThat(list.get(0).get("x")).isEqualTo(12);
105 | assertThat(list.get(1).get("y")).isEqualTo(13);
106 | assertThat(list.get(2).get("z")).isEqualTo(14);
107 | }
108 |
109 | @Test
110 | public void simpleLayoutParameter() {
111 | final BaseParameter base = new BaseParameter();
112 | base.getMeta()
113 | .setTitle("foo");
114 |
115 | final Map map = base.toMap();
116 | assertThat(map).containsKeys("api", "locales", "meta");
117 | assertThat(((Map) map.get("meta")).get("title")).isEqualTo("foo");
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > **Note**: This repo is no longer officially maintained as of Jan, 2023.
2 | > Feel free to use it, fork it and patch it for your own needs.
3 |
4 | ## The Java example app
5 |
6 | [](https://circleci.com/gh/contentful/the-example-app.java)
7 |
8 | The Java example app teaches the very basics of how to work with Contentful:
9 |
10 | - consume content from the Contentful Delivery and Preview APIs
11 | - model content
12 | - edit content through the Contentful web app
13 |
14 | The app demonstrates how decoupling content from its presentation enables greater flexibility and facilitates shipping higher quality software more quickly.
15 |
16 | 
17 |
18 | You can see a hosted version of `The Java example app` on Heroku .
19 |
20 | ## What is Contentful?
21 |
22 | [Contentful](https://www.contentful.com) provides a content infrastructure for digital teams to power content in websites, apps, and devices. Unlike a CMS, Contentful was built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.
23 |
24 | ## Requirements
25 |
26 | * Java (JDK 8+)
27 | * Git
28 | * Contentful CLI (only for write access)
29 |
30 | Without any changes, this app is connected to a Contentful space with read-only access. To experience the full end-to-end Contentful experience, you need to connect the app to a Contentful space with read _and_ write access. This enables you to see how content editing in the Contentful web app works and how content changes propagate to this app.
31 |
32 | ## Common setup
33 |
34 | Clone the repo and install the dependencies.
35 |
36 | ```bash
37 | git clone https://github.com/contentful/the-example-app.java.git
38 | ```
39 |
40 | ## Steps for read-only access
41 |
42 | To start the server, run the following
43 |
44 | ```bash
45 | ./gradlew run
46 | ```
47 |
48 | Open [http://localhost:8080](http://localhost:8080) and take a look around.
49 |
50 |
51 | ## Steps for read and write access (recommended)
52 |
53 | Step 1: Install the [Contentful CLI](https://www.npmjs.com/package/contentful-cli)
54 |
55 | Step 2: Login to Contentful through the CLI. It will help you to create a [free account](https://www.contentful.com/sign-up/) if you don't have one already.
56 | ```
57 | contentful login
58 | ```
59 | Step 3: Create a new space
60 | ```
61 | contentful space create --name 'My space for the example app'
62 | ```
63 | Step 4: Seed the new space with the content model. Replace the `SPACE_ID` with the id returned from the create command executed in step 3
64 | ```
65 | contentful space seed -s '' -t the-example-app
66 | ```
67 | Step 5: Head to the Contentful web app's API section and grab `SPACE_ID`, `DELIVERY_ACCESS_TOKEN`, `PREVIEW_ACCESS_TOKEN`.
68 |
69 | Step 6: Open [application.properties](/src/main/resources/application.properties) and inject your credentials so it looks like this
70 |
71 | ```
72 | spaceId=qz0n5cdakyl9
73 | deliveryToken=580d5944194846b690dd89b630a1cb98a0eef6a19b860ef71efc37ee8076ddb8
74 | previewToken=e8fc39d9661c7468d0285a7ff949f7a23539dd2e686fcb7bd84dc01b392d698b
75 | version=1.0.0
76 | application=The example Java app
77 | ```
78 |
79 | Step 7: To start the server, run the following
80 |
81 | ```bash
82 | ./gradlew run
83 | ```
84 |
85 | Final Step:
86 |
87 | Open [http://localhost:8080?editorial_features=enabled](http://localhost:8080?editorial_features=enabled) and take a look around. This URL flag adds an _Edit_ button in the app on every editable piece of content which will take you back to Contentful web app where you can make changes. It also adds _Draft_ and _Pending Changes_ status indicators to all content if relevant.
88 |
89 | ## Deploy to Heroku
90 | You can also deploy this app to Heroku:
91 |
92 | [](https://heroku.com/deploy)
93 |
94 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/modelconverter/EntryToLandingPage.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.modelconverter;
2 |
3 | import com.contentful.java.cda.CDAAsset;
4 | import com.contentful.java.cda.CDAEntry;
5 | import com.contentful.tea.java.models.landing.LandingPageParameter;
6 | import com.contentful.tea.java.models.landing.modules.BaseModule;
7 | import com.contentful.tea.java.models.landing.modules.CopyModule;
8 | import com.contentful.tea.java.models.landing.modules.HeroImageModule;
9 | import com.contentful.tea.java.models.landing.modules.HighlightedCourseModule;
10 | import com.contentful.tea.java.services.localization.Keys;
11 | import com.contentful.tea.java.services.modelenhancers.EditorialFeaturesEnhancer;
12 |
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.stereotype.Component;
15 |
16 | import java.util.List;
17 |
18 | @Component
19 | public class EntryToLandingPage extends ContentfulModelToMappableTypeConverter {
20 |
21 | @Autowired
22 | @SuppressWarnings("unused")
23 | private EntryToCourse courseConverter;
24 |
25 | @Autowired
26 | @SuppressWarnings("unused")
27 | private EditorialFeaturesEnhancer enhancer;
28 |
29 | @Override
30 | public LandingPageParameter convert(CDAEntry entry, int editorialFeaturesDepth) {
31 | final LandingPageParameter parameter = new LandingPageParameter();
32 | parameter.getBase().getMeta().setTitle(t(Keys.homeLabel));
33 | parameter.getBase().getLabels().setErrorDoesNotExistLabel(t(Keys.errorHighlightedCourse));
34 |
35 | addModules(parameter, entry, editorialFeaturesDepth);
36 |
37 | if (editorialFeaturesDepth > 0) {
38 | enhancer.enhance(entry, parameter.getBase());
39 | }
40 | return parameter;
41 | }
42 |
43 | private void addModules(LandingPageParameter parameter, CDAEntry entry, int editorialFeaturesDepth) {
44 | final List contentModules = entry.getField("contentModules");
45 | if (contentModules == null) {
46 | return;
47 | }
48 |
49 | for (final CDAEntry module : contentModules) {
50 | final BaseModule moduleParameter = createNewModuleParameter(module, editorialFeaturesDepth);
51 |
52 | if (moduleParameter != null) {
53 | parameter.addModule(moduleParameter);
54 | }
55 |
56 | if (editorialFeaturesDepth > 0) {
57 | if (enhancer.isDraft(module)) {
58 | parameter.getBase().getMeta().setDraft(true);
59 | }
60 |
61 | if (enhancer.isPending(module)) {
62 | parameter.getBase().getMeta().setPendingChanges(true);
63 | }
64 | }
65 | }
66 | }
67 |
68 | private BaseModule createNewModuleParameter(CDAEntry module, int editorialFeaturesDepth) {
69 | switch (module.contentType().id()) {
70 | case "layoutCopy":
71 | return new CopyModule()
72 | .setHeadline(module.getField("headline"))
73 | .setCopy(module.getField("copy"))
74 | .setCtaLink(module.getField("ctaLink"))
75 | .setCtaTitle(module.getField("ctaTitle"))
76 | .setEmphasizeStyle("Emphasized".equals(module.getField("visualStyle")))
77 | ;
78 | case "layoutHighlightedCourse":
79 | final CDAEntry course = module.getField("course");
80 | if (course != null) {
81 | return new HighlightedCourseModule()
82 | .setCourse(
83 | courseConverter.convert(
84 | new EntryToCourse.Compound()
85 | .setCourse(course),
86 | editorialFeaturesDepth - 1
87 | ).getCourse());
88 | } else {
89 | return null;
90 | }
91 | case "layoutHeroImage":
92 | return new HeroImageModule()
93 | .setHeadline(module.getField("headline"))
94 | .setBackgroundImageTitle(module.getField("backgroundImageTitle"))
95 | .setBackgroundImageUrl(backgroundImageUrlFromModule(module))
96 | ;
97 | default:
98 | return null;
99 | }
100 | }
101 |
102 | private String backgroundImageUrlFromModule(CDAEntry module) {
103 | final CDAAsset asset = module.getField("backgroundImage");
104 | return asset.url();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/models/LessonsModelTests.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.models;
2 |
3 | import com.contentful.java.cda.CDAEntry;
4 | import com.contentful.tea.java.MainController;
5 | import com.contentful.tea.java.models.courses.lessons.LessonParameter;
6 | import com.contentful.tea.java.models.courses.lessons.modules.CodeModule;
7 | import com.contentful.tea.java.models.courses.lessons.modules.CopyModule;
8 | import com.contentful.tea.java.models.courses.lessons.modules.ImageModule;
9 | import com.contentful.tea.java.services.contentful.Contentful;
10 | import com.contentful.tea.java.services.modelconverter.ArrayToCourses;
11 | import com.contentful.tea.java.services.modelconverter.EntryToLandingPage;
12 | import com.contentful.tea.java.services.modelconverter.EntryToLesson;
13 | import com.contentful.tea.java.services.settings.Settings;
14 | import com.contentful.tea.java.utils.http.EnqueueHttpResponse;
15 | import com.contentful.tea.java.utils.http.EnqueuedHttpResponseTests;
16 |
17 | import org.junit.After;
18 | import org.junit.Before;
19 | import org.junit.Test;
20 | import org.junit.runner.RunWith;
21 | import org.springframework.beans.factory.annotation.Autowired;
22 | import org.springframework.boot.test.context.SpringBootTest;
23 | import org.springframework.boot.test.mock.mockito.MockBean;
24 | import org.springframework.test.context.junit4.SpringRunner;
25 |
26 | import static org.assertj.core.api.Java6Assertions.assertThat;
27 | import static org.mockito.BDDMockito.given;
28 |
29 | @RunWith(SpringRunner.class)
30 | @SpringBootTest(classes = MainController.class)
31 | public class LessonsModelTests extends EnqueuedHttpResponseTests {
32 |
33 | @Autowired
34 | @SuppressWarnings("unused")
35 | private EntryToLandingPage landingPageConverter;
36 |
37 | @Autowired
38 | @SuppressWarnings("unused")
39 | private ArrayToCourses coursesConverter;
40 |
41 | @Autowired
42 | @SuppressWarnings("unused")
43 | private EntryToLesson lessonConverter;
44 |
45 | @MockBean
46 | @SuppressWarnings("unused")
47 | private Contentful contentful;
48 |
49 | @Autowired
50 | @SuppressWarnings("unused")
51 | private Settings settings;
52 |
53 | @Before
54 | public void setup() {
55 | given(this.contentful.getCurrentClient()).willReturn(client);
56 | }
57 |
58 | @After
59 | public void tearDown() {
60 | contentful.reset();
61 | settings.reset();
62 | }
63 |
64 | @Test
65 | @EnqueueHttpResponse({"lessons/complete.json", "defaults/locales.json"})
66 | public void lessonTest() {
67 | settings.setPath("/courses/one_course");
68 | settings.setQueryString("");
69 |
70 | final CDAEntry cdaLesson = client.fetch(CDAEntry.class).one("2SAYsnajosIkCOWqSmKaio");
71 |
72 | final LessonParameter lesson = lessonConverter.convert(cdaLesson, 2);
73 | assertThat(lesson.getSlug()).isEqualTo("complete_lesson");
74 | assertThat(lesson.getTitle()).isEqualTo("Complete Lesson > all the modules");
75 |
76 | assertThat(lesson.getModules()).hasSize(3);
77 |
78 | int i = 0;
79 | assertThat(lesson.getModules().get(i)).isInstanceOf(CopyModule.class);
80 | assertThat(lesson.getModules().get(i).getTitle()).isEqualTo("Complete Lesson > Copy");
81 | assertThat(((CopyModule) lesson.getModules().get(i)).getCopy()).isEqualTo("This is the copy...");
82 | i++;
83 |
84 | assertThat(lesson.getModules().get(i)).isInstanceOf(ImageModule.class);
85 | assertThat(lesson.getModules().get(i).getTitle()).isEqualTo("Complete Lesson > Image Module");
86 | final ImageModule imageModule = (ImageModule) lesson.getModules().get(i);
87 | assertThat(imageModule.getCaption()).isEqualTo("Image Module");
88 | assertThat(imageModule.getImageUrl()).isEqualTo("https://images.contentful.com/jnzexv31feqf/PKYPMsOlqK4SAwEOwMQky/2ccd7c30325fab8a4f34b35cc4e7e427/foo");
89 | i++;
90 |
91 | assertThat(lesson.getModules().get(i)).isInstanceOf(CodeModule.class);
92 | assertThat(lesson.getModules().get(i).getTitle()).isEqualTo("Complete Lesson > Code Module");
93 | final CodeModule codeModule = (CodeModule) lesson.getModules().get(i);
94 | assertThat(codeModule.getCurl()).isEqualTo("curl");
95 | assertThat(codeModule.getJava()).isEqualTo("java");
96 | assertThat(codeModule.getJavaAndroid()).isEqualTo("java-android");
97 | assertThat(codeModule.getJavascript()).isEqualTo("javascript");
98 | assertThat(codeModule.getPhp()).isEqualTo("php");
99 | assertThat(codeModule.getRuby()).isEqualTo("ruby");
100 | assertThat(codeModule.getPython()).isEqualTo("python");
101 | i++;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/resources/templates/settings.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | include mixins/_breadcrumb
4 |
5 | mixin renderError (error)
6 | if error.message
7 | .form-item__error-wrapper
8 | svg.form-item__error-icon
9 | use(xlink:href='/icons/icons.svg#error')
10 | .form-item__error-message= error.message
11 |
12 | block content
13 | .layout-centered-small
14 | +breadcrumb
15 | h1= title
16 | p #{settingsIntroLabel}
17 |
18 | if successful
19 | .status-block.status-block--success
20 | svg.status-block__icon.status-block__icon--success
21 | use(xlink:href='/icons/icons.svg#success')
22 | .status-block__content
23 | .status-block__title #{changesSavedLabel}
24 |
25 | if errors.hasErrors
26 | .status-block.status-block--error
27 | svg.status-block__icon.status-block__icon--error
28 | use(xlink:href='/icons/icons.svg#error')
29 | .status-block__content
30 | .status-block__title #{errorOccurredTitleLabel}
31 | .status-block__message #{errorOccurredMessageLabel}
32 |
33 | if !errors.hasErrors
34 | .status-block.status-block--info
35 | svg.status-block__icon.status-block__icon--info
36 | use(xlink:href='/icons/icons.svg#info')
37 | .status-block__content
38 | .status-block__message
39 | if !usesCustomCredentials
40 | p
41 | em #{usingServerCredentialsLabel}
42 | p
43 | strong #{connectedToSpaceLabel}:
44 | br
45 | span #{spaceName} (#{spaceId})
46 | p
47 | strong #{credentialSourceLabel}:
48 | br
49 | span #{loadedFromLocalFileLabel}
50 | a(href="#{loadedFromLocalFileUrl}" target="_blank" rel="noopener") #{loadedFromLocalFileName}
51 | p
52 | em #{overrideConfigLabel}
53 | else
54 | p
55 | em #{usingSessionCredentialsLabel}
56 | p
57 | strong #{connectedToSpaceLabel}:
58 | br
59 | span #{spaceName} (#{spaceId})
60 |
61 | form(action='/settings?reset=true' method='POST')
62 | p
63 | strong #{applicationCredentialsLabel}:
64 | br
65 | button(type="submit") #{resetCredentialsLabel}
66 | br
67 | a(href='#{deepLinkUrl}' class="status-block__sharelink") #{copyLinkLabel}
68 | p
69 | em #{overrideConfigLabel}
70 |
71 | form(action='/settings!{base.meta.queryString}' method="POST" class="form")
72 | .form-item
73 | label(for="input-space-id") #{spaceIdLabel}
74 | input(type="text" name="space_id" id="input-space-id" required value=settings.spaceId)
75 | if errors.spaceId
76 | +renderError(errors.spaceId)
77 | .form-item__help-text #{spaceIdHelpText}
78 |
79 | .form-item
80 | label(for="input-delivery-token") #{deliveryTokenLabel}
81 | input(type="text" name="delivery_token" id="input-delivery-token" required value=settings.deliveryToken)
82 | if errors.deliveryToken
83 | +renderError(errors.deliveryToken)
84 | .form-item__help-text
85 | | #{contentDeliveryApiHelpText}
86 | a(href='https://www.contentful.com/developers/docs/references/content-delivery-api/' target='_blank' rel='noopener') Content Delivery API.
87 |
88 | .form-item
89 | label(for="input-preview-token") #{previewTokenLabel}
90 | input(type="text" name="preview_token" id="input-preview-token" required value=settings.previewToken)
91 | if errors.previewToken
92 | +renderError(errors.previewToken)
93 | .form-item__help-text
94 | | #{contentPreviewApiHelpText}
95 | a(href='https://www.contentful.com/developers/docs/references/content-preview-api/' target='_blank' rel='noopener') Content Preview API.
96 |
97 | .form-item
98 | if editorialFeaturesEnabled
99 | input(type="checkbox" name="editorial_features" id="input-editorial-features" checked value="enabled")
100 | else
101 | input(type="checkbox" name="editorial_features" id="input-editorial-features" value="enabled")
102 | label(for="input-editorial-features") #{enableEditorialFeaturesLabel}
103 | .form-item__help-text #{enableEditorialFeaturesHelpText}
104 |
105 | .form-item
106 | input.cta(type="submit" value=saveSettingsButtonLabel)
107 |
--------------------------------------------------------------------------------
/src/main/resources/static/images/contentful-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/services/modelenhancers/EditorialFeaturesEnhancer.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.services.modelenhancers;
2 |
3 | import com.contentful.java.cda.CDAClient;
4 | import com.contentful.java.cda.CDAEntry;
5 | import com.contentful.java.cda.CDAHttpException;
6 | import com.contentful.java.cda.CDAResourceNotFoundException;
7 | import com.contentful.java.cda.LocalizedResource;
8 | import com.contentful.tea.java.models.base.BaseParameter;
9 | import com.contentful.tea.java.services.contentful.Contentful;
10 | import com.contentful.tea.java.services.settings.Settings;
11 |
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.stereotype.Component;
14 |
15 | import java.time.LocalDateTime;
16 | import java.time.temporal.ChronoField;
17 | import java.time.temporal.ChronoUnit;
18 | import java.time.temporal.TemporalAccessor;
19 | import java.util.Locale;
20 |
21 | import static com.contentful.tea.java.services.contentful.Contentful.API_CPA;
22 | import static java.lang.String.format;
23 | import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
24 |
25 | @Component
26 | public class EditorialFeaturesEnhancer {
27 | @Autowired
28 | @SuppressWarnings("unused")
29 | private Contentful contentful;
30 |
31 | @Autowired
32 | @SuppressWarnings("unused")
33 | private Settings settings;
34 |
35 | public void enhance(CDAEntry entry, BaseParameter base) {
36 | final boolean editorialFeatures = settings.areEditorialFeaturesEnabled();
37 | if (!base.getMeta().hasEditorialFeatures()) {
38 | base.getMeta().setEditorialFeatures(editorialFeatures);
39 | }
40 |
41 | if (editorialFeatures
42 | && contentful.getApi().equals(API_CPA)
43 | && !base.getMeta().hasPendingChanges()
44 | && !base.getMeta().isDraft()) {
45 | updateDraftAndPendingStates(entry, base);
46 | }
47 |
48 | base
49 | .getMeta()
50 | .setDeeplinkToContentful(generateDeeplinkToContentful(entry));
51 | }
52 |
53 | String generateDeeplinkToContentful(CDAEntry entry) {
54 | final String spaceId = contentful.getSpaceId();
55 | final String entryId = entry.id();
56 | final String contentTypeId = entry.contentType().id();
57 |
58 | return format(Locale.getDefault(),
59 | "https://app.contentful.com/spaces/%s/entries/%s?contentTypeId=%s",
60 | spaceId, entryId, contentTypeId);
61 | }
62 |
63 | private void updateDraftAndPendingStates(CDAEntry currentEntry, BaseParameter base) {
64 | base.getMeta().setDraft(base.getMeta().isDraft() || isDraft(currentEntry));
65 | base.getMeta().setPendingChanges(base.getMeta().hasPendingChanges() || isPending(currentEntry));
66 | }
67 |
68 | public boolean isDraft(CDAEntry previewEntry) {
69 | final String api = contentful.getApi();
70 | try {
71 | final CDAClient client = contentful
72 | .setApi(Contentful.API_CDA)
73 | .getCurrentClient();
74 |
75 | final CDAEntry publishedEntry = client
76 | .fetch(CDAEntry.class)
77 | .one(previewEntry.id());
78 |
79 | if (publishedEntry == null) {
80 | return true;
81 | }
82 | } catch (CDAResourceNotFoundException exception) {
83 | return true;
84 | } catch (CDAHttpException exception) {
85 | if (exception.responseCode() == 404) {
86 | return true;
87 | }
88 | } catch (Throwable t) {
89 | return false;
90 | } finally {
91 | contentful.setApi(api);
92 | }
93 |
94 | return false;
95 | }
96 |
97 | public boolean isPending(CDAEntry previewEntry) {
98 | final String api = contentful.getApi();
99 | try {
100 | final CDAClient client = contentful
101 | .setApi(Contentful.API_CDA)
102 | .getCurrentClient();
103 |
104 | final CDAEntry publishedEntry = client
105 | .fetch(CDAEntry.class)
106 | .one(previewEntry.id());
107 |
108 | if (isPreviewUpdatedMoreRecently(publishedEntry, previewEntry)) {
109 | return true;
110 | }
111 | } catch (Throwable t) {
112 | return false;
113 | } finally {
114 | contentful.setApi(api);
115 | }
116 |
117 | return false;
118 | }
119 |
120 | private boolean isPreviewUpdatedMoreRecently(LocalizedResource publishedEntry, LocalizedResource previewEntry) {
121 | final LocalDateTime publishedUpdatedAtTime = getPublishedAtTime(publishedEntry);
122 | final LocalDateTime previewUpdatedAtTime = getPublishedAtTime(previewEntry);
123 |
124 | return previewUpdatedAtTime.compareTo(publishedUpdatedAtTime) > 0;
125 | }
126 |
127 | private LocalDateTime getPublishedAtTime(LocalizedResource entry) {
128 | final CharSequence updatedAt = entry.getAttribute("updatedAt");
129 | final TemporalAccessor accessor = ISO_DATE_TIME.parse(updatedAt);
130 | final LocalDateTime dateTime = LocalDateTime.from(accessor);
131 | return dateTime.minus(dateTime.get(ChronoField.NANO_OF_SECOND), ChronoUnit.NANOS);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/test/java/com/contentful/tea/java/utils/TestUtils.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.utils;
2 |
3 | import com.contentful.tea.java.models.base.AnalyticsParameter;
4 | import com.contentful.tea.java.models.base.BaseParameter;
5 | import com.contentful.tea.java.models.base.Locale;
6 |
7 | import static org.assertj.core.api.Assertions.assertThat;
8 |
9 | public class TestUtils {
10 | public static void createBaseParameter(BaseParameter base) {
11 | base.getApi()
12 | .setCdaButtonCSSClass("TEST-setCdaButtonCSSClass")
13 | .setCpaButtonCSSClass("TEST-setCpaButtonCSSClass")
14 | .setCurrentApiId("TEST-setCurrentApiId")
15 | ;
16 |
17 | base.getMeta()
18 | .setAllCoursesCssClass("TEST-setAllCoursesCSSClass")
19 | .setCoursesCSSClass("TEST-setCoursesCSSClass")
20 | .setCurrentPath("/TEST-setCurrentPath")
21 | .setHomeCSSClass("TEST-setHomeCSSClass")
22 | .setQueryString("TEST-setQueryString")
23 | .setTitle("TEST-setTitle")
24 | .setUpperMenuCSSClass("TEST-setUpperMenuCSSClass")
25 | .setDeeplinkToContentful("TEST-setDeeplinkToContentful")
26 | .setAllPlatformsQueryString("TEST-allPlatformsQueryString")
27 | .setAnalytics(new AnalyticsParameter().setSpaceId("TEST-spaceID"))
28 | ;
29 |
30 | base.getLocales()
31 | .setCurrentLocaleCode("TEST-setCurrentLocaleCode")
32 | .setCurrentLocaleName("TEST-setCurrentLocaleName")
33 | .addLocale(
34 | new Locale()
35 | .setCode("en-US")
36 | .setName("\uD83C\uDDFA\uD83C\uDDF8")
37 | .setCssClass("inactive")
38 | )
39 | .addLocale(
40 | new Locale()
41 | .setCode("de-DE")
42 | .setName("\uD83C\uDDE9\uD83C\uDDEA")
43 | .setCssClass("active")
44 | );
45 |
46 | base
47 | .getLabels()
48 | .setAllCoursesLabel("TEST-setAllCoursesLabel")
49 | .setApiSwitcherHelp("TEST-setApiSwitcherHelp")
50 | .setCategoriesLabel("TEST-setCategoriesLabel")
51 | .setComingSoonLabel("TEST-setComingSoonLabel")
52 | .setContactUsLabel("TEST-setContactUsLabel")
53 | .setContentDeliveryApiHelp("TEST-setContentDeliveryApiHelp")
54 | .setContentDeliveryApiLabel("TEST-setContentDeliveryApiLabel")
55 | .setContentPreviewApiHelp("TEST-setContentPreviewApiHelp")
56 | .setContentPreviewApiLabel("TEST-setContentPreviewApiLabel")
57 | .setCoursesLabel("TEST-setCoursesLabel")
58 | .setCurrentApiLabel("TEST-setCurrentApiLabel")
59 | .setDescription("TEST-setDescription")
60 | .setDraftLabel("TEST-setDraftLabel")
61 | .setEditInWebAppLabel("TEST-setEditInWebAppLabel")
62 | .setEditorialFeaturesHint("TEST-setEditorialFeaturesHint")
63 | .setFooterDisclaimer("TEST-setFooterDisclaimer")
64 | .setHomeLabel("TEST-setHomeLabel")
65 | .setHostedLabel("TEST-setHostedLabel")
66 | .setImageAlt("TEST-setImageAlt")
67 | .setImageDescription("TEST-setImageDescription")
68 | .setImprintLabel("TEST-setImprintLabel")
69 | .setLocaleLabel("TEST-setLocaleLabel")
70 | .setLocaleQuestion("TEST-setLocaleQuestion")
71 | .setLogoAlt("TEST-setLogoAlt")
72 | .setModalCTALabel("TEST-setModalCTALabel")
73 | .setModalIntro("TEST-setModalIntro")
74 | .setModalPlatforms("TEST-setModalPlatforms")
75 | .setModalSpaceIntro("TEST-setModalSpaceIntro")
76 | .setModalSpaceLinkLabel("TEST-setModalSpaceLinkLabel")
77 | .setModalTitle("TEST-setModalTitle")
78 | .setPendingChangesLabel("TEST-setPendingChangesLabel")
79 | .setSettingsLabel("TEST-setSettingsLabel")
80 | .setTwitterCard("TEST-setTwitterCard")
81 | .setViewCourseLabel("TEST-setViewCourseLabel")
82 | .setViewOnGitHub("TEST-setViewOnGitHub")
83 | .setWhatIsThisApp("TEST-setWhatIsThisApp")
84 | ;
85 | }
86 |
87 | public static void assertBaseParameterInHtml(String generatedHtml) {
88 | assertThat(generatedHtml)
89 | .doesNotContain("\uD83D\uDE31")
90 | .doesNotContain("!{")
91 | .doesNotContain("#{")
92 | .contains(" ")
93 | .contains("\uD83C\uDDE9\uD83C\uDDEA")
94 | .contains("\uD83C\uDDFA\uD83C\uDDF8")
95 | .contains("active")
96 | .contains("de-DE")
97 | .contains("inactive")
98 | .contains("TEST-setCdaButtonCSSClass")
99 | .contains("TEST-setCoursesCSSClass")
100 | .contains("TEST-setCpaButtonCSSClass")
101 | .contains("TEST-setCurrentApiId")
102 | .contains("TEST-setCurrentLocaleCode")
103 | .contains("TEST-setCurrentLocaleName")
104 | .contains("/TEST-setCurrentPath")
105 | .contains("TEST-setHomeCSSClass")
106 | .contains("TEST-setQueryString")
107 | .contains("TEST-setUpperMenuCSSClass")
108 | .contains("TEST-spaceID")
109 | ;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/main/resources/static/icons/icons.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/models/errors/ErrorParameter.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.models.errors;
2 |
3 | import com.contentful.tea.java.models.base.BaseParameter;
4 | import com.contentful.tea.java.models.mappable.MappableType;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.Objects;
9 |
10 | public class ErrorParameter extends MappableType {
11 | private BaseParameter base = new BaseParameter();
12 |
13 | private String responseData;
14 | private String responseDataLabel;
15 | private String stack;
16 | private String somethingWentWrongLabel;
17 | private String stackTraceLabel;
18 | private String tryLabel;
19 | private boolean useCustomCredentials;
20 | private String resetCredentialsLabel;
21 | private int status;
22 | private List hints = new ArrayList<>();
23 |
24 | public BaseParameter getBase() {
25 | return base;
26 | }
27 |
28 | public String getResponseData() {
29 | return responseData;
30 | }
31 |
32 | public ErrorParameter setResponseData(String responseData) {
33 | this.responseData = responseData;
34 | return this;
35 | }
36 |
37 | public String getResponseDataLabel() {
38 | return responseDataLabel;
39 | }
40 |
41 | public ErrorParameter setResponseDataLabel(String responseDataLabel) {
42 | this.responseDataLabel = responseDataLabel;
43 | return this;
44 | }
45 |
46 | public String getStack() {
47 | return stack;
48 | }
49 |
50 | public ErrorParameter setStack(String stack) {
51 | this.stack = stack;
52 | return this;
53 | }
54 |
55 | public String getSomethingWentWrongLabel() {
56 | return somethingWentWrongLabel;
57 | }
58 |
59 | public ErrorParameter setSomethingWentWrongLabel(String somethingWentWrongLabel) {
60 | this.somethingWentWrongLabel = somethingWentWrongLabel;
61 | return this;
62 | }
63 |
64 | public String getStackTraceLabel() {
65 | return stackTraceLabel;
66 | }
67 |
68 | public ErrorParameter setStackTraceLabel(String stackTraceLabel) {
69 | this.stackTraceLabel = stackTraceLabel;
70 | return this;
71 | }
72 |
73 | public int getStatus() {
74 | return status;
75 | }
76 |
77 | public ErrorParameter setStatus(int status) {
78 | this.status = status;
79 | return this;
80 | }
81 |
82 | public String getTryLabel() {
83 | return tryLabel;
84 | }
85 |
86 | public ErrorParameter setTryLabel(String tryLabel) {
87 | this.tryLabel = tryLabel;
88 | return this;
89 | }
90 |
91 | public List getHints() {
92 | return hints;
93 | }
94 |
95 | public ErrorParameter setHints(List hints) {
96 | this.hints.clear();
97 | this.hints.addAll(hints);
98 |
99 | return this;
100 | }
101 |
102 | public ErrorParameter addHint(String hint) {
103 | this.hints.add(hint);
104 | return this;
105 | }
106 |
107 | public boolean usesCustomCredentials() {
108 | return useCustomCredentials;
109 | }
110 |
111 | public ErrorParameter setUseCustomCredentials(boolean useCustomCredentials) {
112 | this.useCustomCredentials = useCustomCredentials;
113 | return this;
114 | }
115 |
116 | public String getResetCredentialsLabel() {
117 | return resetCredentialsLabel;
118 | }
119 |
120 | public ErrorParameter setResetCredentialsLabel(String resetCredentialsLabel) {
121 | this.resetCredentialsLabel = resetCredentialsLabel;
122 | return this;
123 | }
124 |
125 | @Override public boolean equals(Object o) {
126 | if (this == o) return true;
127 | if (!(o instanceof ErrorParameter)) return false;
128 | final ErrorParameter that = (ErrorParameter) o;
129 | return getStatus() == that.getStatus() &&
130 | Objects.equals(getBase(), that.getBase()) &&
131 | Objects.equals(getResponseData(), that.getResponseData()) &&
132 | Objects.equals(getResponseDataLabel(), that.getResponseDataLabel()) &&
133 | Objects.equals(getStack(), that.getStack()) &&
134 | Objects.equals(getSomethingWentWrongLabel(), that.getSomethingWentWrongLabel()) &&
135 | Objects.equals(getTryLabel(), that.getTryLabel()) &&
136 | Objects.equals(getStackTraceLabel(), that.getStackTraceLabel()) &&
137 | Objects.equals(getResetCredentialsLabel(), that.getResetCredentialsLabel()) &&
138 | Objects.equals(usesCustomCredentials(), that.usesCustomCredentials()) &&
139 | Objects.equals(getHints(), that.getHints());
140 | }
141 |
142 | @Override public int hashCode() {
143 | return Objects.hash(getBase(), getResponseData(), getStack(), getStackTraceLabel(), getSomethingWentWrongLabel(), getStackTraceLabel(), getStatus(), getTryLabel());
144 | }
145 |
146 | @Override public String toString() {
147 | return "ErrorParameter { " + super.toString() + " "
148 | + "base = " + getBase() + ", "
149 | + "responseData = " + getResponseData() + ", "
150 | + "stack = " + getStack() + ", "
151 | + "somethingWentWrongLabel = " + getSomethingWentWrongLabel() + ", "
152 | + "stackTraceLabel = " + getStackTraceLabel() + ", "
153 | + "status = " + getStatus() + ", "
154 | + "hints = " + String.join(",", hints) + ", "
155 | + "tryLabel= " + getTryLabel() + " "
156 | + "}";
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/main/java/com/contentful/tea/java/models/courses/CourseParameter.java:
--------------------------------------------------------------------------------
1 | package com.contentful.tea.java.models.courses;
2 |
3 | import com.contentful.tea.java.models.base.BaseParameter;
4 | import com.contentful.tea.java.models.mappable.MappableType;
5 |
6 | import java.util.Objects;
7 |
8 | public class CourseParameter extends MappableType {
9 | private BaseParameter base = new BaseParameter();
10 |
11 | private String tableOfContentsLabel;
12 | private String skillLevelLabel;
13 | private String overviewLabel;
14 | private String courseOverviewLabel;
15 | private String courseOverviewCssClass;
16 | private String durationLabel;
17 | private String minutesLabel;
18 | private String startCourseLabel;
19 | private String nextLessonLabel;
20 | private Course course;
21 |
22 | public BaseParameter getBase() {
23 | return base;
24 | }
25 |
26 | public String getTableOfContentsLabel() {
27 | return tableOfContentsLabel;
28 | }
29 |
30 | public CourseParameter setTableOfContentsLabel(String tableOfContentsLabel) {
31 | this.tableOfContentsLabel = tableOfContentsLabel;
32 | return this;
33 | }
34 |
35 | public String getSkillLevelLabel() {
36 | return skillLevelLabel;
37 | }
38 |
39 | public CourseParameter setSkillLevelLabel(String skillLevelLabel) {
40 | this.skillLevelLabel = skillLevelLabel;
41 | return this;
42 | }
43 |
44 | public String getOverviewLabel() {
45 | return overviewLabel;
46 | }
47 |
48 | public CourseParameter setOverviewLabel(String overviewLabel) {
49 | this.overviewLabel = overviewLabel;
50 | return this;
51 | }
52 |
53 | public String getCourseOverviewLabel() {
54 | return courseOverviewLabel;
55 | }
56 |
57 | public CourseParameter setCourseOverviewLabel(String courseOverviewLabel) {
58 | this.courseOverviewLabel = courseOverviewLabel;
59 | return this;
60 | }
61 |
62 | public String getCourseOverviewCssClass() {
63 | return courseOverviewCssClass;
64 | }
65 |
66 | public CourseParameter setCourseOverviewCssClass(String courseOverviewCssClass) {
67 | this.courseOverviewCssClass = courseOverviewCssClass;
68 | return this;
69 | }
70 |
71 | public String getDurationLabel() {
72 | return durationLabel;
73 | }
74 |
75 | public CourseParameter setDurationLabel(String durationLabel) {
76 | this.durationLabel = durationLabel;
77 | return this;
78 | }
79 |
80 | public String getMinutesLabel() {
81 | return minutesLabel;
82 | }
83 |
84 | public CourseParameter setMinutesLabel(String minutesLabel) {
85 | this.minutesLabel = minutesLabel;
86 | return this;
87 | }
88 |
89 | public String getStartCourseLabel() {
90 | return startCourseLabel;
91 | }
92 |
93 | public CourseParameter setStartCourseLabel(String startCourseLabel) {
94 | this.startCourseLabel = startCourseLabel;
95 | return this;
96 | }
97 |
98 | public Course getCourse() {
99 | return course;
100 | }
101 |
102 | public CourseParameter setCourse(Course course) {
103 | this.course = course;
104 | return this;
105 | }
106 |
107 | public String getNextLessonLabel() {
108 | return nextLessonLabel;
109 | }
110 |
111 | public CourseParameter setNextLessonLabel(String nextLessonLabel) {
112 | this.nextLessonLabel = nextLessonLabel;
113 | return this;
114 | }
115 |
116 | @Override public boolean equals(Object o) {
117 | if (this == o) return true;
118 | if (!(o instanceof CourseParameter)) return false;
119 | final CourseParameter that = (CourseParameter) o;
120 | return Objects.equals(getTableOfContentsLabel(), that.getTableOfContentsLabel()) &&
121 | Objects.equals(getSkillLevelLabel(), that.getSkillLevelLabel()) &&
122 | Objects.equals(getCourseOverviewLabel(), that.getCourseOverviewLabel()) &&
123 | Objects.equals(getCourseOverviewCssClass(), that.getCourseOverviewCssClass()) &&
124 | Objects.equals(getOverviewLabel(), that.getOverviewLabel()) &&
125 | Objects.equals(getDurationLabel(), that.getDurationLabel()) &&
126 | Objects.equals(getMinutesLabel(), that.getMinutesLabel()) &&
127 | Objects.equals(getStartCourseLabel(), that.getStartCourseLabel()) &&
128 | Objects.equals(getNextLessonLabel(), that.getNextLessonLabel()) &&
129 | Objects.equals(getCourse(), that.getCourse());
130 | }
131 |
132 | @Override public int hashCode() {
133 | return Objects.hash(getTableOfContentsLabel(), getSkillLevelLabel(), getCourseOverviewLabel(), getCourseOverviewCssClass(), getOverviewLabel(), getDurationLabel(), getMinutesLabel(), getStartCourseLabel(), getNextLessonLabel(), getCourse());
134 | }
135 |
136 | @Override public String toString() {
137 | return "CourseParameter { " + super.toString() + " "
138 | + "durationLabel = " + getDurationLabel() + ", "
139 | + "course = " + getCourse() + ", "
140 | + "minutesLabel = " + getMinutesLabel() + ", "
141 | + "courseOverViewLabel = " + getCourseOverviewLabel() + ", "
142 | + "courseOverviewCssClass = " + getCourseOverviewCssClass() + ", "
143 | + "overviewLabel = " + getOverviewLabel() + ", "
144 | + "skillLevelLabel = " + getSkillLevelLabel() + ", "
145 | + "startCourseLabel = " + getStartCourseLabel() + ", "
146 | + "tableOfContentsLabel = " + getTableOfContentsLabel() + ", "
147 | + "nextLessonLabel= " + getNextLessonLabel() + " "
148 | + "}";
149 | }
150 | }
151 |
--------------------------------------------------------------------------------