From e8aaf2542a800f48e430b009e85cbc509430a4f4 Mon Sep 17 00:00:00 2001 From: ljupcovangelski Date: Tue, 27 Apr 2021 15:17:23 +0200 Subject: [PATCH 01/28] Bump version to 0.20.0-alpha --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1cf0537c34..4863f59c36 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.19.0 +0.20.0-alpha From de1ae1c60dff266cef9e382f1a4728e54e2e98ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Apr 2021 09:43:38 +0200 Subject: [PATCH 02/28] Bump @types/node from 15.0.0 to 15.0.1 (#1662) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 15.0.0 to 15.0.1. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d8c713ab35..0dba2670eb 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@crello/react-lottie": "^0.0.11", "@reduxjs/toolkit": "^1.5.1", "@stomp/stompjs": "^6.1.0", - "@types/node": "15.0.0", + "@types/node": "15.0.1", "@types/react": "16.9.34", "@types/react-dom": "16.9.2", "@types/react-redux": "7.1.16", diff --git a/yarn.lock b/yarn.lock index a1a2347323..a5efdf401e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1357,10 +1357,10 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== -"@types/node@*", "@types/node@15.0.0": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.0.tgz#557dd0da4a6dca1407481df3bbacae0cd6f68042" - integrity sha512-YN1d+ae2MCb4U0mMa+Zlb5lWTdpFShbAj5nmte6lel27waMMBfivrm0prC16p/Di3DyTrmerrYUT8/145HXxVw== +"@types/node@*", "@types/node@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" + integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== "@types/node@^10.1.0": version "10.17.55" From 587aba686da40dd2c687a89a91cbf463ce003f29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Apr 2021 09:43:54 +0200 Subject: [PATCH 03/28] Bump webpack from 5.35.1 to 5.36.0 (#1663) Bumps [webpack](https://github.com/webpack/webpack) from 5.35.1 to 5.36.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.35.1...v5.36.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 0dba2670eb..ff1e04c7be 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "terser-webpack-plugin": "^5.1.1", "typescript": "3.7.4", "url-loader": "^4.1.1", - "webpack": "^5.35.1", + "webpack": "^5.36.0", "webpack-bundle-analyzer": "^4.4.1", "webpack-cli": "^4.6.0", "webpack-dev-server": "^3.11.2" diff --git a/yarn.lock b/yarn.lock index a5efdf401e..6b53f0c0e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1719,10 +1719,10 @@ acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4: - version "8.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe" - integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA== +acorn@^8.0.4, acorn@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.1.tgz#0d36af126fb6755095879c1dc6fd7edf7d60a5fb" + integrity sha512-z716cpm5TX4uzOzILx8PavOE6C6DKshHDw1aQN52M/yNSqE9s5O8SMfyhCCfCJ3HmTL0NkVOi+8a/55T7YB3bg== ajv-errors@^1.0.0: version "1.0.1" @@ -7687,17 +7687,17 @@ webpack-sources@^2.1.1: source-list-map "^2.0.1" source-map "^0.6.1" -webpack@^5.35.1: - version "5.35.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.35.1.tgz#857670799465c8a5cbb94c4c175d60ac42d18ba3" - integrity sha512-uWKYStqJ23+N6/EnMEwUjPSSKUG1tFmcuKhALEh/QXoUxwN8eb3ATNIZB38A+fO6QZ0xfc7Cu7KNV9LXNhDCsw== +webpack@^5.36.0: + version "5.36.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.36.0.tgz#d008da31b721f8fecce88ef2adaf1b16dc2161d1" + integrity sha512-HdOhLXClUEwTnzQnzpSG9iL00ej23ojvfnGpF49ba0MkuAT2q+WhQilHFFJHOIVRBqbzakQ1vCWQV2K+QLX0Qw== dependencies: "@types/eslint-scope" "^3.7.0" "@types/estree" "^0.0.47" "@webassemblyjs/ast" "1.11.0" "@webassemblyjs/wasm-edit" "1.11.0" "@webassemblyjs/wasm-parser" "1.11.0" - acorn "^8.0.4" + acorn "^8.2.1" browserslist "^4.14.5" chrome-trace-event "^1.0.2" enhanced-resolve "^5.8.0" From ebc6591beb93ebdae39699f7618bcea638da1057 Mon Sep 17 00:00:00 2001 From: Christoph Proeschel Date: Wed, 28 Apr 2021 10:07:37 +0200 Subject: [PATCH 04/28] [#1661] Fix token name in docs (#1664) --- docs/docs/getting-started/installation/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/getting-started/installation/configuration.md b/docs/docs/getting-started/installation/configuration.md index 3525c2edfc..3b9433113d 100644 --- a/docs/docs/getting-started/installation/configuration.md +++ b/docs/docs/getting-started/installation/configuration.md @@ -57,8 +57,8 @@ cluster and Redis. ### Security -- `token` set to a long secure secret to use for machine [API authentication](api/authentication.md) (default: random generated) -- `allowedOrigins` your sites origin to prevent CORS-based attacks (default: "\*") +- `systemToken` set to a long secure secret to use for machine [API authentication](api/authentication.md) +- `allowedOrigins` your site's origin to prevent CORS-based attacks (default: `"*"`) ### Components From 8e1614c5b572c39321d6a336ec0479a72872e8b8 Mon Sep 17 00:00:00 2001 From: Christoph Proeschel Date: Wed, 28 Apr 2021 11:55:20 +0200 Subject: [PATCH 05/28] [#1666] Fix chatplugin cors config (#1667) Fixes #1666 --- .../main/java/co/airy/core/chat_plugin/config/AuthConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java index bf29f44e88..e1e3c865b6 100644 --- a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java +++ b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java @@ -49,7 +49,7 @@ CorsConfigurationSource corsConfigurationSource(final Environment environment) { final String allowed = environment.getProperty("allowedOrigins", ""); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOrigin(allowed); + config.addAllowedOriginPattern(allowed); config.addAllowedHeader("*"); config.setAllowedMethods(List.of("GET", "POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); From 86c930f0ed759bb5bc1250466293e6cc8c9d6236 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Apr 2021 15:21:08 +0200 Subject: [PATCH 06/28] Bump @types/react from 16.9.34 to 17.0.4 (#1658) Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 16.9.34 to 17.0.4. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 21 ++++----------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index ff1e04c7be..bd7b9f70f7 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@reduxjs/toolkit": "^1.5.1", "@stomp/stompjs": "^6.1.0", "@types/node": "15.0.1", - "@types/react": "16.9.34", + "@types/react": "17.0.4", "@types/react-dom": "16.9.2", "@types/react-redux": "7.1.16", "@types/react-router-dom": "^5.1.7", diff --git a/yarn.lock b/yarn.lock index 6b53f0c0e2..eeef997137 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1436,23 +1436,15 @@ dependencies: "@types/react" "*" -"@types/react@*": - version "17.0.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.3.tgz#ba6e215368501ac3826951eef2904574c262cc79" - integrity sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg== +"@types/react@*", "@types/react@17.0.4": + version "17.0.4" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.4.tgz#a67c6f7a460d2660e950d9ccc1c2f18525c28220" + integrity sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@16.9.34": - version "16.9.34" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349" - integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - "@types/resize-observer-browser@^0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz#36d897708172ac2380cd486da7a3daf1161c1e23" @@ -2741,11 +2733,6 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -csstype@^2.2.0: - version "2.6.16" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.16.tgz#544d69f547013b85a40d15bff75db38f34fe9c39" - integrity sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q== - csstype@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" From 848ab185cdca5f477fc80320e08e590b28185381 Mon Sep 17 00:00:00 2001 From: Thorsten Date: Wed, 28 Apr 2021 15:46:51 +0200 Subject: [PATCH 07/28] [#1525] Update quick filter (#1660) --- .../src/actions/conversationsFilter/index.ts | 5 + .../ui/src/components/Tag/index.module.scss | 1 + .../pages/Inbox/ConversationList/index.tsx | 4 +- .../ConversationListHeader/index.module.scss | 23 +++- .../Inbox/ConversationListHeader/index.tsx | 57 ++++++-- .../Inbox/ConversationListItem/index.tsx | 13 +- .../ConversationsFilter/Popup.module.scss | 28 ++-- .../pages/Inbox/ConversationsFilter/Popup.tsx | 68 ++++++++-- .../ConversationsFilter/index.module.scss | 38 +++++- .../pages/Inbox/ConversationsFilter/index.tsx | 124 +++++------------- frontend/ui/src/selectors/conversations.ts | 86 +++++++++++- lib/typescript/model/ConversationFilter.ts | 1 + 12 files changed, 301 insertions(+), 147 deletions(-) diff --git a/frontend/ui/src/actions/conversationsFilter/index.ts b/frontend/ui/src/actions/conversationsFilter/index.ts index caca7492de..c244b7cd1e 100644 --- a/frontend/ui/src/actions/conversationsFilter/index.ts +++ b/frontend/ui/src/actions/conversationsFilter/index.ts @@ -110,5 +110,10 @@ const filterToLuceneSyntax = (filter: ConversationFilter): string | null => { if (filter.bySources && filter.bySources.length > 0) { filterQuery.push('source:(' + filter.bySources.join(' OR ') + ')'); } + if (filter.isStateOpen === true) { + filterQuery.push('id:* AND NOT metadata.state:CLOSED'); + } else if (filter.isStateOpen !== undefined) { + filterQuery.push('metadata.state:CLOSED'); + } return !filterQuery.length ? null : filterQuery.join(' AND '); }; diff --git a/frontend/ui/src/components/Tag/index.module.scss b/frontend/ui/src/components/Tag/index.module.scss index 94c42ce3dc..375fa4ee9a 100644 --- a/frontend/ui/src/components/Tag/index.module.scss +++ b/frontend/ui/src/components/Tag/index.module.scss @@ -15,6 +15,7 @@ line-height: 24px; max-width: 100%; white-space: nowrap; + border: 1px solid transparent; &:hover { word-break: break-all; diff --git a/frontend/ui/src/pages/Inbox/ConversationList/index.tsx b/frontend/ui/src/pages/Inbox/ConversationList/index.tsx index 6d38517e01..883d793c1b 100644 --- a/frontend/ui/src/pages/Inbox/ConversationList/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationList/index.tsx @@ -117,8 +117,8 @@ const ConversationList = (props: ConversationListProps) => {
- - resizeList()} /> + resizeList()} /> +
{renderConversationList()}
diff --git a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss index e81dd14cfa..dff4a0cf1f 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss +++ b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss @@ -10,8 +10,9 @@ .containerSearchHeadline { display: flex; justify-content: space-between; - height: 40px; + height: 42px; width: 100%; + align-items: center; } .containerSearchField { @@ -65,6 +66,7 @@ border: none; background-color: white; cursor: pointer; + outline: none; } .headline { @@ -76,12 +78,27 @@ .searchIcon { width: 22px; height: 22px; - padding-top: 2px; + padding-top: 1px; margin-right: 4px; position: relative; - top: 8px; path { fill: var(--color-text-gray); } } + +.filterButton { + cursor: pointer; + background: none; + border: none; + outline: none; +} + +.activeFilters { + @extend .filterButton; + svg { + path { + fill: var(--color-airy-blue); + } + } +} diff --git a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx index 90d61f2b4f..40e3394d0e 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx @@ -1,5 +1,6 @@ import React, {useEffect, useState} from 'react'; -import {connect, ConnectedProps} from 'react-redux'; +import _, {connect, ConnectedProps} from 'react-redux'; +import {RouteComponentProps} from 'react-router-dom'; import {SearchField} from 'components'; import {StateModel} from '../../../reducers'; @@ -8,31 +9,37 @@ import {setSearch, resetFilteredConversationAction} from '../../../actions/conve import {ReactComponent as IconSearch} from 'assets/images/icons/search.svg'; import {ReactComponent as BackIcon} from 'assets/images/icons/arrow-left-2.svg'; +import {ReactComponent as FilterIcon} from 'assets/images/icons/filter-alt.svg'; import styles from './index.module.scss'; import {cySearchButton, cySearchField, cySearchFieldBackButton} from 'handles'; - -const mapStateToProps = (state: StateModel) => { - return { - user: state.data.user, - currentFilter: state.data.conversations.filtered.currentFilter || {}, - totalConversations: state.data.conversations.all.paginationData.total, - }; -}; +import Popup from '../ConversationsFilter/Popup'; const mapDispatchToProps = { setSearch, resetFilteredConversationAction, }; +const mapStateToProps = (state: StateModel) => ({ + user: state.data.user, + currentFilter: state.data.conversations.filtered.currentFilter || {}, + totalConversations: state.data.conversations.all.paginationData.total, +}); + const connector = connect(mapStateToProps, mapDispatchToProps); -const ConversationListHeader = (props: ConnectedProps) => { - const {setSearch, resetFilteredConversationAction, currentFilter} = props; +type ConversationListHeaderProps = { + onFilterVisibilityChanged: () => void; +} & ConnectedProps & + RouteComponentProps; + +const ConversationListHeader = (props: ConversationListHeaderProps) => { + const {setSearch, resetFilteredConversationAction, currentFilter, onFilterVisibilityChanged} = props; const [isShowingSearchInput, setIsShowingSearchInput] = useState(false); const [searchText, setSearchText] = useState(''); + const [isFilterOpen, setIsFilterOpen] = useState(false); useEffect(() => { resetFilteredConversationAction(); @@ -66,6 +73,22 @@ const ConversationListHeader = (props: ConnectedProps) => { return
{`Inbox (${totalConversations})`}
; }; + const toggleFilter = () => { + setIsFilterOpen(!isFilterOpen); + onFilterVisibilityChanged(); + }; + + const activeFilter = () => { + const currentFilterLength = Object.keys(currentFilter).length; + + if (currentFilter.isStateOpen === undefined && currentFilter.displayName === (null || undefined)) { + return currentFilterLength - 2; + } + if (currentFilter.isStateOpen === undefined || currentFilter.displayName === (null || undefined)) { + return currentFilterLength - 1; + } + }; + const renderSearchInput = isShowingSearchInput ? (
+ + {isFilterOpen && ( +
+ +
+ )}
); diff --git a/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx b/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx index 5a76b16cc6..a7225d1f47 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx @@ -8,12 +8,13 @@ import {Avatar} from 'render'; import {formatTimeOfMessage} from '../../../services/format/date'; import {Message} from 'model'; -import {MergedConversation} from '../../../reducers'; +import {MergedConversation, StateModel} from '../../../reducers'; import {INBOX_CONVERSATIONS_ROUTE} from '../../../routes/routes'; import {readConversations, conversationState} from '../../../actions/conversations'; import styles from './index.module.scss'; import {ReactComponent as Checkmark} from 'assets/images/icons/checkmark-circle.svg'; +import {newestFilteredConversationFirst} from '../../../selectors/conversations'; interface FormattedMessageProps { message: Message; @@ -30,7 +31,13 @@ const mapDispatchToProps = { conversationState, }; -const connector = connect(null, mapDispatchToProps); +const mapStateToProps = (state: StateModel) => { + return { + filteredConversations: newestFilteredConversationFirst(state), + }; +}; + +const connector = connect(mapStateToProps, mapDispatchToProps); const FormattedMessage = ({message}: FormattedMessageProps) => { if (message?.content) { @@ -75,7 +82,7 @@ const ConversationListItem = (props: ConversationListItemProps) => { if (active && unread) { return readConversations(conversation.id); } - }, [active, conversation]); + }, [active, conversation, currentConversationState]); return (
readConversations(conversation.id)}> diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss index bebcf247ee..45bec7968d 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss @@ -72,6 +72,8 @@ display: flex; align-items: center; cursor: pointer; + outline: none; + max-height: 29px; svg { display: inline-block; @@ -83,16 +85,15 @@ fill: var(--color-soft-green); } } +} - .openIcon { - display: inline-block; - width: 15px; - height: 15px; - background: none; - border: 2px solid #bf1a2f; - border-radius: 50%; - margin-right: 6px; - } +.openIconButton { + width: 19px; + height: 19px; + background: none; + border: 2px solid #bf1a2f; + border-radius: 50%; + margin-right: 2px; } .filterButtonSelected { @@ -100,6 +101,7 @@ border: 1px solid var(--color-airy-blue); background-color: var(--color-airy-blue); color: white; + outline: none; path { stroke: white; @@ -194,10 +196,12 @@ } svg { - width: 8px; - height: 6px; - margin-left: 8px; + width: 24px; + height: 24px; margin-bottom: 2px; + border-radius: 50%; + padding-top: 2px; + padding-left: 2px; } } diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx index 4d1d93bc06..77f2ad412b 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx @@ -9,6 +9,7 @@ import {StateModel} from '../../../reducers'; import DialogCustomizable from '../../../components/DialogCustomizable'; import Tag from '../../../components/Tag'; import {ReactComponent as CheckmarkIcon} from 'assets/images/icons/checkmark.svg'; +import {ReactComponent as CheckmarkCircleIcon} from 'assets/images/icons/checkmark-circle.svg'; import styles from './Popup.module.scss'; import {allChannels} from '../../../selectors/channels'; import ChannelAvatar from '../../../components/ChannelAvatar'; @@ -70,6 +71,13 @@ const PopUpFilter = (props: PopUpFilterProps) => { setFilter(newFilter); }; + const toggleState = (event: React.MouseEvent, isOpen: boolean) => { + event.stopPropagation(); + const newFilter: ConversationFilter = {...filter}; + newFilter.isStateOpen === isOpen ? (newFilter.isStateOpen = !isOpen) : (newFilter.isStateOpen = isOpen); + setFilter(newFilter); + }; + const isChannelSelected = (channelsList: Array, channel: Channel) => { return (channelsList || []).includes(channel.id); }; @@ -97,6 +105,10 @@ const PopUpFilter = (props: PopUpFilterProps) => { }); }; + const OpenIcon = () => { + return
; + }; + return ( applyPressed()} @@ -104,19 +116,48 @@ const PopUpFilter = (props: PopUpFilterProps) => { coverStyle={{backgroundColor: 'rgba(247,247,247,0.7)'}}>
-
-

Read/Unread

-
- - +
+
+

Read/Unread

+
+ + +
+
+
+
+
+

State

+
+ + +
@@ -170,7 +211,6 @@ const PopUpFilter = (props: PopUpFilterProps) => { ) : ( )} -
{channel.metadata?.name || channel.sourceChannelId}
))} diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss index 6f134b7206..66125b9a33 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss @@ -1,14 +1,38 @@ @import 'assets/scss/colors.scss'; @import 'assets/scss/fonts.scss'; -.actionRow { +.quickFilterContainer { display: flex; - flex-direction: row; - justify-content: space-between; - flex-grow: 1; - z-index: 3; - position: relative; - min-height: 36px; + align-items: center; +} + +.quickFilterButtons { + display: flex; + width: 100%; + justify-content: center; +} + +.quickFilterButtonsBackground { + border-radius: 8px; + background-color: var(--color-background-gray); +} + +.quickFilterButton { + @include font-base; + background: var(--color-background-gray); + border: none; + outline: none; + border-radius: 8px; + padding: 2px; + width: 80px; + border: 1px solid transparent; + cursor: pointer; +} + +.quickFilterButtonActive { + @extend .quickFilterButton; + background-color: var(--color-background-blue); + border: 1px solid var(--color-airy-blue); } .shortcutButton { diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx index 65a41d23ac..81edd65d57 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx @@ -1,16 +1,12 @@ -import React, {useEffect, useState} from 'react'; +import React, {useEffect, useRef} from 'react'; import _, {connect, ConnectedProps} from 'react-redux'; -import {filter} from 'lodash-es'; import {ConversationFilter} from 'model'; import {StateModel} from '../../../reducers'; -import {setFilter, resetFilter} from '../../../actions/conversationsFilter'; +import {setFilter} from '../../../actions/conversationsFilter'; import {allConversations, isFilterActive} from '../../../selectors/conversations'; -import {ReactComponent as ChevronLeft} from 'assets/images/icons/chevron_left.svg'; -import Popup from './Popup'; - import styles from './index.module.scss'; const mapStateToProps = (state: StateModel) => { @@ -24,86 +20,42 @@ const mapStateToProps = (state: StateModel) => { const mapDispatchToProps = { setFilter, - resetFilter, }; const connector = connect(mapStateToProps, mapDispatchToProps); -type ConversationsFilterProps = { - onFilterVisibilityChanged: () => void; -} & ConnectedProps; +type ConversationsFilterProps = {} & ConnectedProps; const ConversationsFilter = (props: ConversationsFilterProps) => { - const {conversationsFilter, setFilter, onFilterVisibilityChanged} = props; - - const [isFilterOpen, setIsFilterOpen] = useState(false); + const {conversationsFilter, setFilter} = props; + const allButton = useRef(null); + const openButton = useRef(null); + const closedButton = useRef(null); useEffect(() => { - resetFilter(); itemsCount(); + currentStateFilter(); }), [props.conversations]; - const toggleFilter = () => { - setIsFilterOpen(!isFilterOpen); - onFilterVisibilityChanged(); - }; - - const getActiveFilterCount = () => { - return filter(Object.keys(conversationsFilter), (element: string) => { - return element !== 'displayName'; - }).length; - }; - - const isOnlyOneFilterActive = () => { - return getActiveFilterCount() === 1; - }; - - const isFilterUnreadActive = () => { - return conversationsFilter.unreadOnly && isOnlyOneFilterActive(); - }; - - const isFilterButtonActive = () => { - return ( - getActiveFilterCount() > 1 || - conversationsFilter.unreadOnly || - (conversationsFilter.byTags && conversationsFilter.byTags.length > 0) || - (conversationsFilter.byChannels && conversationsFilter.byChannels.length > 0) - ); - }; - - const activateUnreadFilter = () => { - resetFilter(); - const filter: ConversationFilter = {unreadOnly: true}; - setFilter(filter); - }; - - const renderFilterStatus = () => { - const activeFilters = []; - if (conversationsFilter.readOnly) { - activeFilters.push('Read'); - } - if (conversationsFilter.unreadOnly) { - activeFilters.push('Unread'); - } - if (conversationsFilter.byTags && conversationsFilter.byTags.length > 0) { - activeFilters.push(`${conversationsFilter.byTags.length} Tags`); - } - if (conversationsFilter.byChannels && conversationsFilter.byChannels.length > 0) { - activeFilters.push(`${conversationsFilter.byChannels.length} Channels`); + const currentStateFilter = () => { + allButton.current.className = styles.quickFilterButton; + openButton.current.className = styles.quickFilterButton; + closedButton.current.className = styles.quickFilterButton; + + if (conversationsFilter.isStateOpen === undefined) { + allButton.current.className = styles.quickFilterButtonActive; + } else if (conversationsFilter.isStateOpen === true) { + openButton.current.className = styles.quickFilterButtonActive; + } else if (conversationsFilter.isStateOpen === false) { + closedButton.current.className = styles.quickFilterButtonActive; } + }; - return ( -
- {activeFilters.map((filter, key) => { - return ( -
- {filter} -
- ); - })} -
- ); + const setStateOpen = (setOpen: boolean) => { + const newFilter: ConversationFilter = {...conversationsFilter}; + newFilter.isStateOpen = setOpen; + setFilter(newFilter); }; const itemsCount = () => { @@ -126,31 +78,21 @@ const ConversationsFilter = (props: ConversationsFilterProps) => { return (
{itemsCount()} -
- {isFilterButtonActive() ? ( - renderFilterStatus() - ) : ( -
- - +
- )} -
-
- {isFilterOpen && }
); }; diff --git a/frontend/ui/src/selectors/conversations.ts b/frontend/ui/src/selectors/conversations.ts index ea73408af4..c6805a23df 100644 --- a/frontend/ui/src/selectors/conversations.ts +++ b/frontend/ui/src/selectors/conversations.ts @@ -1,6 +1,6 @@ import _, {createSelector} from 'reselect'; import {filter, pickBy, reverse, sortBy, values} from 'lodash-es'; -import {Conversation} from 'model'; +import {Conversation, ConversationFilter} from 'model'; import {MergedConversation, StateModel} from '../reducers'; import {ConversationMap} from '../reducers/data/conversations'; import {ConversationRouteProps} from '../pages/Inbox'; @@ -35,10 +35,88 @@ export const newestConversationFirst = createSelector(allConversations, conversa }); export const newestFilteredConversationFirst = createSelector( - filteredConversationSelector, - (conversations: Conversation[]) => { + (state: StateModel) => state.data.conversations.all.items, + (state: StateModel) => state.data.conversations.filtered.items, + (state: StateModel) => state.data.conversations.filtered.currentFilter, + (conversationsMap: ConversationMap, filteredConversationsMap: ConversationMap, currentFilter: ConversationFilter) => { + const conversations = Object.keys(conversationsMap).map((cId: string) => ({...conversationsMap[cId]})); + const filteredConversations = Object.keys(filteredConversationsMap).map((cId: string) => ({ + ...filteredConversationsMap[cId], + })); + + const updatedConversations: ConversationMap = {}; + + filteredConversations.forEach((filteredConversation: Conversation) => { + if (conversationsMap[filteredConversation.id]) { + updatedConversations[filteredConversation.id] = conversationsMap[filteredConversation.id]; + } else { + updatedConversations[filteredConversation.id] = filteredConversationsMap[filteredConversation.id]; + } + }); + + conversations.forEach((conversation: Conversation) => { + if (!updatedConversations[conversation.id]) { + updatedConversations[conversation.id] = conversation; + } + }); + + const updatedFiltered = filter(updatedConversations, (conversation: Conversation) => { + let isFulfilled = true; + + if (currentFilter.isStateOpen !== undefined) { + if (currentFilter.isStateOpen) { + isFulfilled = conversation.metadata.state === 'OPEN' || conversation.metadata.state === undefined; + } else { + isFulfilled = conversation.metadata.state === 'CLOSED'; + } + if (!isFulfilled) return isFulfilled; + } + + if (currentFilter.readOnly) { + isFulfilled = conversation.metadata.unreadCount === 0; + } else if (currentFilter.unreadOnly) { + isFulfilled = conversation.metadata.unreadCount > 0; + } + + if (currentFilter.byTags) { + const conversationTags = Object.keys(conversation.metadata.tags || {}).map((id: string) => id); + const filterTags = Object.keys(currentFilter.byTags).map((id: string) => currentFilter.byTags[id]); + + isFulfilled = filterTags.every(function (tag) { + return conversationTags.indexOf(tag) >= 0; + }); + } + + if (currentFilter.byChannels?.length > 0) { + const channelId = conversation.channel.id; + const filterChannel = Object.keys(currentFilter.byChannels).map((id: string) => currentFilter.byChannels[id]); + + isFulfilled = filterChannel.includes(channelId); + } + + if (currentFilter.bySources?.length > 0) { + const conversationSource = conversation.channel.source; + const filterSource = Object.keys(currentFilter.bySources).map((id: string) => currentFilter.bySources[id]); + + isFulfilled = filterSource.includes(conversationSource); + } + + if (currentFilter.displayName) { + const searchValue = currentFilter.displayName.toLowerCase(); + const displayName = conversation.metadata.contact.displayName.toLowerCase(); + + isFulfilled = displayName.includes(searchValue); + } + if (!isFulfilled) return isFulfilled; + + return isFulfilled; + }); + return reverse( - sortBy(conversations, (conversation: Conversation) => conversation.lastMessage && conversation.lastMessage.sentAt) + sortBy( + updatedFiltered, + (conversation: Conversation) => conversation.lastMessage && conversation.lastMessage.sentAt + ) ); } ); diff --git a/lib/typescript/model/ConversationFilter.ts b/lib/typescript/model/ConversationFilter.ts index 2382f83c00..6cd3eefde5 100644 --- a/lib/typescript/model/ConversationFilter.ts +++ b/lib/typescript/model/ConversationFilter.ts @@ -6,4 +6,5 @@ export interface ConversationFilter { byTags?: string[]; byChannels?: string[]; bySources?: string[]; + isStateOpen?: boolean; } From 8db19bb932e00b873aebdc6d4a778d37916f2e4a Mon Sep 17 00:00:00 2001 From: Pascal Holy <54705263+pascal-airy@users.noreply.github.com> Date: Wed, 28 Apr 2021 15:48:30 +0200 Subject: [PATCH 08/28] [#1495] Add kafka Prometheus exporter (#1668) Resolves #1495 --- docs/docs/guides/operations.md | 5 ++- .../kafka/charts/kafka/templates/_helpers.tpl | 28 ++++++++--------- .../kafka/templates/headless-service.yaml | 8 ++--- .../kafka/templates/nodeport-service.yaml | 10 +++--- .../kafka/charts/kafka/templates/service.yaml | 11 ++++--- .../charts/kafka/templates/statefulset.yaml | 31 +++++++++++++------ .../charts/kafka/charts/kafka/values.yaml | 5 ++- infrastructure/tools/prometheus/values.yaml | 9 ++++++ 8 files changed, 68 insertions(+), 39 deletions(-) diff --git a/docs/docs/guides/operations.md b/docs/docs/guides/operations.md index b3ef55fb38..25a1781f99 100644 --- a/docs/docs/guides/operations.md +++ b/docs/docs/guides/operations.md @@ -70,7 +70,10 @@ Access Grafana under `/grafana` and login with the If the `defaultDashboardsEnabled` is set to true you can find the default Kubernetes dashboards under `/grafana/dashboards` -For the spring apps we recommend to import this (dashboard)[https://grafana.com/grafana/dashboards/12464]. +For the spring apps we recommend to import this +(dashboard)[https://grafana.com/grafana/dashboards/12464]. + +And for Kafka this (dashboard)[https://grafana.com/grafana/dashboards/7589]. ### Monitoring with alerts diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl index 1d89a598b5..8e20b25515 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl @@ -2,7 +2,7 @@ {{/* Expand the name of the chart. */}} -{{- define "cp-kafka.name" -}} +{{- define "kafka.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -11,7 +11,7 @@ Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} -{{- define "cp-kafka.fullname" -}} +{{- define "kafka.fullname" -}} {{- if .Values.fullnameOverride -}} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} {{- else -}} @@ -27,7 +27,7 @@ If release name contains chart name it will be used as a full name. {{/* Create chart name and version as used by the chart label. */}} -{{- define "cp-kafka.chart" -}} +{{- define "kafka.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -35,8 +35,8 @@ Create chart name and version as used by the chart label. Create a default fully qualified zookeeper name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). */}} -{{- define "cp-kafka.cp-zookeeper.fullname" -}} -{{- $name := default "zookeeper" (index .Values "cp-zookeeper" "nameOverride") -}} +{{- define "kafka.zookeeper.fullname" -}} +{{- $name := default "zookeeper" (index .Values "zookeeper" "nameOverride") -}} {{- printf "%s-headless" $name | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -44,12 +44,12 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this Form the Zookeeper URL. If zookeeper is installed as part of this chart, use k8s service discovery, else use user-provided URL */}} -{{- define "cp-kafka.cp-zookeeper.service-name" }} -{{- if (index .Values "cp-zookeeper" "enabled") -}} -{{- $clientPort := default 2181 (index .Values "cp-zookeeper" "clientPort") | int -}} -{{- printf "%s:%d" (include "cp-kafka.cp-zookeeper.fullname" .) $clientPort }} +{{- define "kafka.zookeeper.service-name" }} +{{- if (index .Values "zookeeper" "enabled") -}} +{{- $clientPort := default 2181 (index .Values "zookeeper" "clientPort") | int -}} +{{- printf "%s:%d" (include "kafka.zookeeper.fullname" .) $clientPort }} {{- else -}} -{{- $zookeeperConnect := printf "%s" (index .Values "cp-zookeeper" "url") }} +{{- $zookeeperConnect := printf "%s" (index .Values "zookeeper" "url") }} {{- $zookeeperConnectOverride := (index .Values "configurationOverrides" "zookeeper.connect") }} {{- default $zookeeperConnect $zookeeperConnectOverride }} {{- end -}} @@ -59,7 +59,7 @@ else use user-provided URL Form the Advertised Listeners. We will use the value of nodeport.firstListenerPort to create the external advertised listeners if configurationOverrides.advertised.listeners is not set. */}} -{{- define "cp-kafka.configuration.advertised.listeners" }} +{{- define "kafka.configuration.advertised.listeners" }} {{- if (index .Values "configurationOverrides" "advertised.listeners") -}} {{- printf ",%s" (first (pluck "advertised.listeners" .Values.configurationOverrides)) }} {{- else -}} @@ -71,8 +71,8 @@ external advertised listeners if configurationOverrides.advertised.listeners is Create a default fully qualified kafka headless name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). */}} -{{- define "cp-kafka.cp-kafka-headless.fullname" -}} -{{- $name := "cp-kafka-headless" -}} +{{- define "kafka.kafka-headless.fullname" -}} +{{- $name := "kafka-headless" -}} {{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -80,7 +80,7 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this Create a variable containing all the datadirs created. */}} -{{- define "cp-kafka.log.dirs" -}} +{{- define "kafka.log.dirs" -}} {{- range $k, $e := until (.Values.persistence.disksPerBroker|int) -}} {{- if $k}}{{- printf ","}}{{end}} {{- printf "/opt/kafka/data-%d/logs" $k -}} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml index afc113e0fe..79c04ff7db 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml @@ -1,11 +1,11 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "cp-kafka.fullname" . }}-headless + name: {{ template "kafka.fullname" . }}-headless namespace: {{ .Values.global.namespace }} labels: - app: {{ template "cp-kafka.name" . }} - chart: {{ template "cp-kafka.chart" . }} + app: {{ template "kafka.name" . }} + chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: @@ -14,5 +14,5 @@ spec: name: broker clusterIP: None selector: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml index 6c439b8270..1395e58323 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml @@ -1,5 +1,5 @@ {{- if .Values.nodeport.enabled }} - {{- $fullName := include "cp-kafka.fullname" . }} + {{- $fullName := include "kafka.fullname" . }} {{- $brokers := .Values.brokers | int }} {{- $servicePort := .Values.nodeport.servicePort }} {{- $root := . }} @@ -10,11 +10,11 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "cp-kafka.fullname" $root }}-{{ $i }}-nodeport" + name: "{{ template "kafka.fullname" $root }}-{{ $i }}-nodeport" namespace: {{ $root.Values.global.namespace }} labels: - app: {{ include "cp-kafka.name" $root }} - chart: {{ template "cp-kafka.chart" $root }} + app: {{ include "kafka.name" $root }} + chart: {{ template "kafka.chart" $root }} release: {{ $root.Release.Name }} heritage: {{ $root.Release.Service }} pod: {{ $responsiblePod }} @@ -27,7 +27,7 @@ spec: nodePort: {{ $externalListenerPort }} protocol: TCP selector: - app: {{ include "cp-kafka.name" $root }} + app: {{ include "kafka.name" $root }} release: {{ $root.Release.Name }} statefulset.kubernetes.io/pod-name: {{ $responsiblePod | quote }} {{- end }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml index addfb0bee8..fc15f7ad50 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml @@ -1,17 +1,20 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "cp-kafka.fullname" . }} + name: {{ template "kafka.fullname" . }} namespace: {{ .Values.global.namespace }} labels: - app: {{ template "cp-kafka.name" . }} - chart: {{ template "cp-kafka.chart" . }} + app: {{ template "kafka.name" . }} + chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + core.airy.co/prometheus: kafka spec: ports: - port: 9092 name: broker + - port: {{ .Values.prometheusExporterPort }} + name: prometheus selector: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml index 0bcd67ca55..d2d70ff0ab 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml @@ -5,21 +5,21 @@ apiVersion: apps/v1beta1 {{- end }} kind: StatefulSet metadata: - name: {{ template "cp-kafka.fullname" . }} + name: {{ template "kafka.fullname" . }} namespace: {{ .Values.global.namespace }} labels: - app: {{ template "cp-kafka.name" . }} - chart: {{ template "cp-kafka.chart" . }} + app: {{ template "kafka.name" . }} + chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: {{- if .Capabilities.APIVersions.Has "apps/v1" }} selector: matchLabels: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} {{- end }} - serviceName: {{ template "cp-kafka.fullname" . }}-headless + serviceName: {{ template "kafka.fullname" . }}-headless podManagementPolicy: {{ .Values.podManagementPolicy }} replicas: {{ default 3 .Values.brokers }} updateStrategy: @@ -27,7 +27,7 @@ spec: template: metadata: labels: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} spec: affinity: @@ -40,14 +40,14 @@ spec: - key: "app" operator: In values: - - {{ template "cp-kafka.name" . }} + - {{ template "kafka.name" . }} - key: "release" operator: In values: - {{ .Release.Name }} topologyKey: "kubernetes.io/hostname" containers: - - name: {{ template "cp-kafka.name" . }}-broker + - name: {{ template "kafka.name" . }}-broker image: "{{ .Values.image }}:{{ .Values.imageTag }}" imagePullPolicy: "{{ .Values.imagePullPolicy }}" ports: @@ -83,13 +83,13 @@ spec: - name: AIRY_LISTENERS value: PLAINTEXT://0.0.0.0:9092,EXTERNAL://0.0.0.0:AIRY_BROKER_PORT - name: AIRY_ADVERTISED_LISTENERS - value: PLAINTEXT://AIRY_POD_NAME.{{ template "cp-kafka.fullname" . }}-headless.AIRY_NAMESPACE:9092,EXTERNAL://AIRY_HOST_IP:AIRY_BROKER_PORT + value: PLAINTEXT://AIRY_POD_NAME.{{ template "kafka.fullname" . }}-headless.AIRY_NAMESPACE:9092,EXTERNAL://AIRY_HOST_IP:AIRY_BROKER_PORT - name: AIRY_FIRST_LISTENER_PORT value: "{{ .Values.firstListenerPort }}" - name: KAFKA_HEAP_OPTS value: {{ .Values.heapOptions }} - name: KAFKA_ZOOKEEPER_CONNECT - value: {{ include "cp-kafka.cp-zookeeper.service-name" . | quote }} + value: {{ include "kafka.zookeeper.service-name" . | quote }} {{- range $key, $value := .Values.configurationOverrides }} - name: {{ printf "KAFKA_%s" $key | replace "." "_" | upper | quote }} value: {{ $value | quote }} @@ -103,6 +103,17 @@ spec: mountPath: /opt/kafka/data-{{$k}} {{- end }} {{- end }} + - name: prometheus + image: "{{ .Values.prometheusExporterImage }}:{{ .Values.prometheusExporterImageTag }}" + resources: + requests: + cpu: 100m + memory: 100Mi + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + ports: + - containerPort: {{ .Values.prometheusExporterPort }} + name: prometheus + {{- if .Values.imagePullSecrets }} imagePullSecrets: {{ toYaml .Values.imagePullSecrets | indent 8 }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml index 5a0fc937ab..cd91ac5b60 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml @@ -24,7 +24,7 @@ nodeport: enabled: true servicePort: 19092 firstListenerPort: 31090 -cp-zookeeper: +zookeeper: enabled: true servers: 1 persistence: @@ -32,3 +32,6 @@ cp-zookeeper: dataDirSize: 5Gi dataLogDirSize: 5Gi url: "" +prometheusExporterImage: danielqsj/kafka-exporter +prometheusExporterImageTag: v1.3.0 +prometheusExporterPort: 9308 \ No newline at end of file diff --git a/infrastructure/tools/prometheus/values.yaml b/infrastructure/tools/prometheus/values.yaml index 622f7ff6ed..c7d8b6d14f 100644 --- a/infrastructure/tools/prometheus/values.yaml +++ b/infrastructure/tools/prometheus/values.yaml @@ -32,3 +32,12 @@ prometheus: - port: web interval: 30s path: actuator/prometheus + - name: "kafka" + selector: + matchLabels: + core.airy.co/prometheus: kafka + namespaceSelector: + matchNames: ["default"] + endpoints: + - port: prometheus + interval: 30s From ea641ff86fb2056d45b1ded84af3dd1d3b752437 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 09:31:18 +0200 Subject: [PATCH 09/28] Bump sass from 1.32.11 to 1.32.12 (#1673) Bumps [sass](https://github.com/sass/dart-sass) from 1.32.11 to 1.32.12. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.32.11...1.32.12) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bd7b9f70f7..19f207a503 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "minimist": "^1.2.5", "prettier": "^2.2.1", "react-hot-loader": "^4.13.0", - "sass": "^1.32.11", + "sass": "^1.32.12", "sass-loader": "^11", "style-loader": "^2.0.0", "terser-webpack-plugin": "^5.1.1", diff --git a/yarn.lock b/yarn.lock index eeef997137..07ab00cb14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6462,10 +6462,10 @@ sass-loader@^11: klona "^2.0.4" neo-async "^2.6.2" -sass@^1.32.11: - version "1.32.11" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.11.tgz#b236b3ea55c76602c2ef2bd0445f0db581baa218" - integrity sha512-O9tRcob/fegUVSIV1ihLLZcftIOh0AF1VpKgusUfLqnb2jQ0GLDwI5ivv1FYWivGv8eZ/AwntTyTzjcHu0c/qw== +sass@^1.32.12: + version "1.32.12" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.12.tgz#a2a47ad0f1c168222db5206444a30c12457abb9f" + integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA== dependencies: chokidar ">=3.0.0 <4.0.0" From 06043a2950bdbbf3bd1b7a3db3e8ff5e8d92c209 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 09:31:30 +0200 Subject: [PATCH 10/28] Bump core-js from 3.11.0 to 3.11.1 (#1672) Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.11.0 to 3.11.1. - [Release notes](https://github.com/zloirock/core-js/releases) - [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/zloirock/core-js/commits/v3.11.1/packages/core-js) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 07ab00cb14..185749717f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2628,9 +2628,9 @@ core-js-compat@^3.9.0, core-js-compat@^3.9.1: semver "7.0.0" core-js@3: - version "3.11.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.0.tgz#05dac6aa70c0a4ad842261f8957b961d36eb8926" - integrity sha512-bd79DPpx+1Ilh9+30aT5O1sgpQd4Ttg8oqkqi51ZzhedMM1omD2e6IOF48Z/DzDCZ2svp49tN/3vneTK6ZBkXw== + version "3.11.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.1.tgz#f920392bf8ed63a0ec8e4e729857bfa3d121c525" + integrity sha512-k93Isqg7e4txZWMGNYwevZL9MiogLk8pd1PtwrmFmi8IBq4GXqUaVW/a33Llt6amSI36uSjd0GWwc9pTT9ALlQ== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" From af2f588086f28a993e1b9cf25c25acf8546b1443 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 09:31:42 +0200 Subject: [PATCH 11/28] Bump @bazel/typescript from 3.4.1 to 3.4.2 (#1671) Bumps [@bazel/typescript](https://github.com/bazelbuild/rules_nodejs/tree/HEAD/packages/typescript) from 3.4.1 to 3.4.2. - [Release notes](https://github.com/bazelbuild/rules_nodejs/releases) - [Changelog](https://github.com/bazelbuild/rules_nodejs/blob/stable/CHANGELOG.md) - [Commits](https://github.com/bazelbuild/rules_nodejs/commits/3.4.2/packages/typescript) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 19f207a503..3c4ba7a60a 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", "@bazel/bazelisk": "^1.8.0", - "@bazel/typescript": "^3.4.1", + "@bazel/typescript": "^3.4.2", "@svgr/webpack": "^5.5.0", "@types/lodash-es": "^4.17.4", "@types/react-window-infinite-loader": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 185749717f..fac7a936b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -979,10 +979,10 @@ resolved "https://registry.yarnpkg.com/@bazel/bazelisk/-/bazelisk-1.8.0.tgz#7bdb7c7068d4779ba8ddbf8cd72afb9b2099bb6e" integrity sha512-RcovBpVPlLptW/+j1+Xbnr4+Ooy1HO8bG2ECAC0pegLvKFWhO6X3twLKKAJ2KQ4jkoeE0xzUUWIL9zyaIsNxLA== -"@bazel/typescript@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.1.tgz#ec52292b240157cd2d874ff7ea7857da8416c00c" - integrity sha512-OKpfjFRhudsaUBL3xH1oAbat+bwdRyfAOTn2qgMQSO3vR4ZBBVYk7GVMJzWamLkbDS0aY5ws5wLfDScJSKD2ww== +"@bazel/typescript@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.2.tgz#183cb14d1f4149cc67ed2723c4b8a7366da5ec36" + integrity sha512-JtLdPOC7rytALJBxawxTCnxVopGstk2eXFs56zHBy+JWSeqrnwujeWZyK5qZHzpag02/JtIQ/ZKkM/DQtrXC8Q== dependencies: protobufjs "6.8.8" semver "5.6.0" From 3416782d41b90be2f0214b2ec99edd47b0638d95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 09:31:52 +0200 Subject: [PATCH 12/28] Bump webpack from 5.36.0 to 5.36.1 (#1670) Bumps [webpack](https://github.com/webpack/webpack) from 5.36.0 to 5.36.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.36.0...v5.36.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3c4ba7a60a..fe6a8a043a 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "terser-webpack-plugin": "^5.1.1", "typescript": "3.7.4", "url-loader": "^4.1.1", - "webpack": "^5.36.0", + "webpack": "^5.36.1", "webpack-bundle-analyzer": "^4.4.1", "webpack-cli": "^4.6.0", "webpack-dev-server": "^3.11.2" diff --git a/yarn.lock b/yarn.lock index fac7a936b9..e2843a0cfd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7674,10 +7674,10 @@ webpack-sources@^2.1.1: source-list-map "^2.0.1" source-map "^0.6.1" -webpack@^5.36.0: - version "5.36.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.36.0.tgz#d008da31b721f8fecce88ef2adaf1b16dc2161d1" - integrity sha512-HdOhLXClUEwTnzQnzpSG9iL00ej23ojvfnGpF49ba0MkuAT2q+WhQilHFFJHOIVRBqbzakQ1vCWQV2K+QLX0Qw== +webpack@^5.36.1: + version "5.36.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.36.1.tgz#d82bad3384f84ed45a8de3844c31730f56361ab7" + integrity sha512-2u25a82T+6quAxSlzEpN/R/RICwt20ONU3z3Ko05S8KVH9FXILcBYb2hD/rQtZT5y7lRAIsIIs05pdndY7ourQ== dependencies: "@types/eslint-scope" "^3.7.0" "@types/estree" "^0.0.47" From 97666de4aa0428470bccdd734e55ccfb350ffc8a Mon Sep 17 00:00:00 2001 From: lucapette Date: Thu, 29 Apr 2021 12:41:46 +0200 Subject: [PATCH 13/28] [#1615] Expose tag events via websocket (#1624) Fixes #1615 --- backend/BUILD | 8 --- backend/api/admin/BUILD | 2 +- .../airy/core/api/admin/TagsController.java | 16 +----- .../payload/ListTagsResponsePayload.java | 2 +- .../api/admin/payload/TagResponsePayload.java | 16 ------ .../core/api/admin/TagsControllerTest.java | 46 ++++++++------- backend/api/websocket/BUILD | 1 + .../co/airy/core/api/websocket/Stores.java | 12 ++-- .../api/websocket/WebSocketController.java | 6 ++ .../websocket/WebSocketControllerTest.java | 36 ++++++++++-- backend/avro/BUILD | 3 +- backend/model/event/BUILD | 1 + .../co/airy/model/event/payload/Event.java | 5 +- .../co/airy/model/event/payload/TagEvent.java | 24 ++++++++ backend/model/tag/BUILD | 19 +++++++ .../java/co/airy/model/tag/TagPayload.java | 25 +++++++++ docs/docs/api/endpoints/chatplugin.md | 16 +++--- docs/docs/api/endpoints/messages.md | 8 +-- docs/docs/api/endpoints/metadata.md | 8 ++- docs/docs/api/endpoints/tags.md | 11 ++-- docs/docs/api/websocket.md | 19 ++++++- .../ui/src/actions/conversations/index.ts | 4 +- frontend/ui/src/actions/metadata/index.ts | 6 -- frontend/ui/src/actions/tags/index.tsx | 23 ++------ .../ui/src/components/AiryWebsocket/index.tsx | 13 +++-- .../ui/src/components/ChannelAvatar/index.tsx | 2 +- .../ConnectedChannelsBySourceCard/index.tsx | 5 +- .../Channels/ConnectedChannelsList/index.tsx | 2 +- .../ui/src/pages/Channels/MainPage/index.tsx | 16 ++---- .../Providers/Twilio/TwilioConnect.tsx | 2 +- .../Twilio/WhatsApp/TwilioWhatsappConnect.tsx | 2 +- .../Messenger/ConversationMetadata/index.tsx | 56 +++++++------------ .../Inbox/Messenger/MessageList/index.tsx | 4 +- frontend/ui/src/pages/Tags/SimpleTagForm.tsx | 6 +- frontend/ui/src/pages/Tags/index.tsx | 39 +++++-------- .../src/reducers/data/conversations/index.ts | 32 +---------- .../ui/src/reducers/data/messages/index.ts | 32 +---------- frontend/ui/src/reducers/data/tags/index.ts | 47 ++++------------ frontend/ui/src/selectors/tags.ts | 21 ------- lib/typescript/httpclient/README.md | 34 +---------- .../httpclient/src/endpoints/createTag.ts | 14 ----- .../httpclient/src/endpoints/deleteTag.ts | 1 - .../httpclient/src/endpoints/listTags.ts | 12 +--- lib/typescript/model/Conversation.ts | 8 --- lib/typescript/model/Source.ts | 2 +- lib/typescript/websocketclient/index.ts | 10 +++- lib/typescript/websocketclient/payload.ts | 50 ++++++++--------- 47 files changed, 303 insertions(+), 424 deletions(-) delete mode 100644 backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java create mode 100644 backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java create mode 100644 backend/model/tag/BUILD create mode 100644 backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java delete mode 100644 frontend/ui/src/selectors/tags.ts diff --git a/backend/BUILD b/backend/BUILD index 004eb75715..29bd98d74f 100644 --- a/backend/BUILD +++ b/backend/BUILD @@ -32,14 +32,6 @@ java_library( ], ) -java_library( - name = "tag", - exports = [ - "//backend/avro:tag", - "//lib/java/kafka/schema:application-communication-tags", - ], -) - java_library( name = "webhook", exports = [ diff --git a/backend/api/admin/BUILD b/backend/api/admin/BUILD index 9f5867e4f4..a51240b54f 100644 --- a/backend/api/admin/BUILD +++ b/backend/api/admin/BUILD @@ -7,7 +7,7 @@ app_deps = [ "//backend:base_app", "//:springboot_actuator", "//backend/model/channel", - "//backend:tag", + "//backend/model/tag", "//backend:webhook", "//backend/model/metadata", "//backend/model/template", diff --git a/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java b/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java index 61b10b17e8..27aa2f120e 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java @@ -5,7 +5,7 @@ import co.airy.core.api.admin.payload.CreateTagRequestPayload; import co.airy.core.api.admin.payload.DeleteTagRequestPayload; import co.airy.core.api.admin.payload.ListTagsResponsePayload; -import co.airy.core.api.admin.payload.TagResponsePayload; +import co.airy.core.api.admin.payload.TagPayload; import co.airy.core.api.admin.payload.UpdateTagRequestPayload; import co.airy.spring.web.payload.RequestErrorResponsePayload; import org.apache.kafka.streams.state.KeyValueIterator; @@ -62,11 +62,7 @@ ResponseEntity createTag(@RequestBody @Valid CreateTagRequestPayload payload) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } - return ResponseEntity.status(201).body(TagResponsePayload.builder() - .id(tag.getId()) - .name(tag.getName()) - .color(tag.getColor().toString()) - .build()); + return ResponseEntity.status(201).body(TagPayload.fromTag(tag)); } @PostMapping("/tags.list") @@ -77,13 +73,7 @@ ResponseEntity listTags() { List tags = new ArrayList<>(); iterator.forEachRemaining(kv -> tags.add(kv.value)); - final List data = tags.stream() - .map(tag -> TagResponsePayload.builder() - .id(tag.getId()) - .name(tag.getName()) - .color(tag.getColor().toString()) - .build() - ).collect(toList()); + final List data = tags.stream().map(TagPayload::fromTag).collect(toList()); return ResponseEntity.ok().body(ListTagsResponsePayload.builder().data(data).build()); } diff --git a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java b/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java index bd9c628e8a..c04add3def 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java @@ -12,5 +12,5 @@ @AllArgsConstructor @Builder public class ListTagsResponsePayload { - private List data; + private List data; } diff --git a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java b/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java deleted file mode 100644 index 5968bc618e..0000000000 --- a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java +++ /dev/null @@ -1,16 +0,0 @@ -package co.airy.core.api.admin.payload; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class TagResponsePayload { - private String id; - private String name; - private String color; -} diff --git a/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java b/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java index 068c50e123..2ddbf3acc0 100644 --- a/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java +++ b/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java @@ -23,8 +23,7 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -import java.util.concurrent.TimeUnit; - +import static co.airy.test.Timing.retryOnException; import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -74,7 +73,7 @@ void beforeEach() throws Exception { @Test void canManageTags() throws Exception { - final String name = "awesome-tag"; + final String name = "flag"; final String color = "tag-red"; final String payload = "{\"name\":\"" + name + "\",\"color\": \"" + color + "\"}"; @@ -87,34 +86,33 @@ void canManageTags() throws Exception { final JsonNode jsonNode = objectMapper.readTree(createTagResponse); final String tagId = jsonNode.get("id").textValue(); - //TODO wait for tag to be there - TimeUnit.SECONDS.sleep(5); - webTestHelper.post("/tags.list", "{}") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.length()", is(1))) - .andExpect(jsonPath("$.data[0].id").value(is(tagId))) - .andExpect(jsonPath("$.data[0].name").value(is(name))) - .andExpect(jsonPath("$.data[0].color").value(is("RED"))); + retryOnException(() -> + webTestHelper.post("/tags.list", "{}") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.length()", is(1))) + .andExpect(jsonPath("$.data[0].id").value(is(tagId))) + .andExpect(jsonPath("$.data[0].name").value(is(name))) + .andExpect(jsonPath("$.data[0].color").value(is("tag-red"))), + "could not create tag"); webTestHelper.post("/tags.update", - "{\"id\": \"" + tagId + "\", \"name\": \"new-name\", \"color\": \"" + color + "\"}") + "{\"id\": \"" + tagId + "\", \"name\": \"new-flag\", \"color\": \"" + color + "\"}") .andExpect(status().isNoContent()); - webTestHelper.post("/tags.list", "{}") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.length()", is(1))) - .andExpect(jsonPath("$.data[0].id").value(is(tagId))) - .andExpect(jsonPath("$.data[0].name").value(is("new-name"))) - .andExpect(jsonPath("$.data[0].color").value(is("RED"))); + retryOnException(() -> webTestHelper.post("/tags.list", "{}") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.length()", is(1))) + .andExpect(jsonPath("$.data[0].id").value(is(tagId))) + .andExpect(jsonPath("$.data[0].name").value(is("new-flag"))) + .andExpect(jsonPath("$.data[0].color").value(is("tag-red"))), + "could not update tag"); webTestHelper.post("/tags.delete", "{\"id\": \"" + tagId + "\"}").andExpect(status().isNoContent()); - //TODO wait for tag deletion - TimeUnit.SECONDS.sleep(5); - - webTestHelper.post("/tags.list", "{}") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.length()", is(0))); + retryOnException(() -> webTestHelper.post("/tags.list", "{}") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.length()", is(0))), + "could not delete tag"); } } diff --git a/backend/api/websocket/BUILD b/backend/api/websocket/BUILD index b92e0ba082..b51ddf2590 100644 --- a/backend/api/websocket/BUILD +++ b/backend/api/websocket/BUILD @@ -11,6 +11,7 @@ app_deps = [ "//backend/model/event", "//backend/model/message", "//backend/model/metadata", + "//backend/model/tag", "//lib/java/date", "//lib/java/spring/auth:spring-auth", "//lib/java/spring/web:spring-web", diff --git a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java index 65a973f692..bd2b36c0b8 100644 --- a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java +++ b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java @@ -3,9 +3,11 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; +import co.airy.avro.communication.Tag; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; +import co.airy.kafka.schema.application.ApplicationCommunicationTags; import co.airy.kafka.streams.KafkaStreamsWrapper; import co.airy.model.metadata.dto.MetadataMap; import org.apache.kafka.streams.KeyValue; @@ -22,13 +24,11 @@ @Component public class Stores implements HealthIndicator, ApplicationListener, DisposableBean { - private static final String appId = "api.WebsocketStores"; + private static final String appId = "api.WebSocketStores"; private final KafkaStreamsWrapper streams; private final WebSocketController webSocketController; - Stores(KafkaStreamsWrapper streams, - WebSocketController webSocketController - ) { + Stores(KafkaStreamsWrapper streams, WebSocketController webSocketController) { this.streams = streams; this.webSocketController = webSocketController; } @@ -43,6 +43,10 @@ public void onApplicationEvent(ApplicationStartedEvent event) { builder.stream(new ApplicationCommunicationChannels().name()) .peek((channelId, channel) -> webSocketController.onChannel(channel)); + builder.stream(new ApplicationCommunicationTags().name()) + .filter((id, tag) -> tag != null) + .peek((id, tag) -> webSocketController.onTag(tag)); + builder.table(new ApplicationCommunicationMetadata().name()) .groupBy((metadataId, metadata) -> KeyValue.pair(getSubject(metadata).getIdentifier(), metadata)) .aggregate(MetadataMap::new, MetadataMap::adder, MetadataMap::subtractor) diff --git a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java index 0f189c4826..feb4cc1b2a 100644 --- a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java +++ b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java @@ -2,10 +2,12 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.Message; +import co.airy.avro.communication.Tag; import co.airy.model.channel.ChannelPayload; import co.airy.model.event.payload.ChannelEvent; import co.airy.model.event.payload.MessageEvent; import co.airy.model.event.payload.MetadataEvent; +import co.airy.model.event.payload.TagEvent; import co.airy.model.metadata.dto.MetadataMap; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; @@ -38,4 +40,8 @@ public void onMetadata(MetadataMap metadataMap) { messagingTemplate.convertAndSend(QUEUE_EVENTS, MetadataEvent.fromMetadataMap(metadataMap)); } + + public void onTag(Tag tag) { + messagingTemplate.convertAndSend(QUEUE_EVENTS, TagEvent.fromTag(tag)); + } } diff --git a/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java b/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java index 90a9e03560..213acc37b1 100644 --- a/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java +++ b/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java @@ -5,14 +5,18 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; +import co.airy.avro.communication.Tag; +import co.airy.avro.communication.TagColor; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; +import co.airy.kafka.schema.application.ApplicationCommunicationTags; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; import co.airy.model.event.payload.ChannelEvent; import co.airy.model.event.payload.MessageEvent; import co.airy.model.event.payload.MetadataEvent; +import co.airy.model.event.payload.TagEvent; import co.airy.spring.core.AirySpringBootApplication; import co.airy.spring.test.WebTestHelper; import com.fasterxml.jackson.databind.ObjectMapper; @@ -51,7 +55,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {AirySpringBootApplication.class}) @@ -65,11 +68,11 @@ public class WebSocketControllerTest { private static final ApplicationCommunicationMessages applicationCommunicationMessages = new ApplicationCommunicationMessages(); private static final ApplicationCommunicationChannels applicationCommunicationChannels = new ApplicationCommunicationChannels(); private static final ApplicationCommunicationMetadata applicationCommunicationMetadata = new ApplicationCommunicationMetadata(); + private static final ApplicationCommunicationTags applicationCommunicationTags = new ApplicationCommunicationTags(); @Value("${local.server.port}") private int port; - @Autowired private WebTestHelper webTestHelper; @@ -78,7 +81,8 @@ static void beforeAll() throws Exception { kafkaTestHelper = new KafkaTestHelper(sharedKafkaTestResource, applicationCommunicationMessages, applicationCommunicationChannels, - applicationCommunicationMetadata + applicationCommunicationMetadata, + applicationCommunicationTags ); kafkaTestHelper.beforeAll(); } @@ -94,7 +98,7 @@ void beforeEach() throws Exception { } @Test - void canReceiveMessageEvents() throws Exception { + void canSendMessageEvents() throws Exception { final CompletableFuture future = subscribe(port, MessageEvent.class, QUEUE_EVENTS); final Message message = Message.newBuilder() .setId("messageId") @@ -120,7 +124,7 @@ void canReceiveMessageEvents() throws Exception { } @Test - void canReceiveChannelEvents() throws Exception { + void canSendChannelEvents() throws Exception { final CompletableFuture future = subscribe(port, ChannelEvent.class, QUEUE_EVENTS); final Channel channel = Channel.newBuilder() @@ -138,7 +142,7 @@ void canReceiveChannelEvents() throws Exception { } @Test - void canReceiveMetadataEvents() throws Exception { + void canSendMetadataEvents() throws Exception { final CompletableFuture future = subscribe(port, MetadataEvent.class, QUEUE_EVENTS); final Metadata metadata = Metadata.newBuilder() @@ -157,6 +161,26 @@ void canReceiveMetadataEvents() throws Exception { assertThat(recMetadata.getPayload().getMetadata().get("contact").get("displayName").textValue(), equalTo(metadata.getValue())); } + @Test + void canSendTagEvents() throws Exception { + final CompletableFuture future = subscribe(port, TagEvent.class, QUEUE_EVENTS); + + String tagId=UUID.randomUUID().toString(); + final Tag tag = Tag.newBuilder() + .setId(tagId) + .setName("flag") + .setColor(TagColor.RED) + .build(); + + kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationTags.name(), tagId, tag)); + + TagEvent tagEvent = future.get(30, TimeUnit.SECONDS); + assertNotNull(tagEvent); + assertThat(tagEvent.getPayload().getId(), equalTo(tagId)); + assertThat(tagEvent.getPayload().getName(), equalTo("flag")); + assertThat(tagEvent.getPayload().getColor(), equalTo("tag-red")); + } + private static StompSession connectToWs(int port) throws ExecutionException, InterruptedException { final WebSocketStompClient stompClient = new WebSocketStompClient(new StandardWebSocketClient()); MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter(); diff --git a/backend/avro/BUILD b/backend/avro/BUILD index 77f06c43aa..d79dfd54d2 100644 --- a/backend/avro/BUILD +++ b/backend/avro/BUILD @@ -27,7 +27,8 @@ avro_java_library( ) avro_java_library( - name = "tag", + name = "tag-avro", + srcs = ["tag.avsc"], ) avro_java_library( diff --git a/backend/model/event/BUILD b/backend/model/event/BUILD index 8faff392a8..5158888b6b 100644 --- a/backend/model/event/BUILD +++ b/backend/model/event/BUILD @@ -11,6 +11,7 @@ custom_java_library( "//backend/model/channel", "//backend/model/message", "//backend/model/metadata", + "//backend/model/tag", ], ) diff --git a/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java b/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java index aae28c1c68..f374ee61bd 100644 --- a/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java +++ b/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java @@ -3,11 +3,12 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = MessageEvent.class, name = "message"), @JsonSubTypes.Type(value = MetadataEvent.class, name = "metadata"), - @JsonSubTypes.Type(value = ChannelEvent.class, name = "channel") + @JsonSubTypes.Type(value = ChannelEvent.class, name = "channel"), + @JsonSubTypes.Type(value = TagEvent.class, name = "tag") }) public abstract class Event { } diff --git a/backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java b/backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java new file mode 100644 index 0000000000..d0624611e8 --- /dev/null +++ b/backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java @@ -0,0 +1,24 @@ +package co.airy.model.event.payload; + +import co.airy.avro.communication.Tag; +import co.airy.core.api.admin.payload.TagPayload; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class TagEvent extends Event implements Serializable { + private TagPayload payload; + + public static TagEvent fromTag(Tag tag) { + return builder().payload(TagPayload.fromTag(tag)).build(); + } +} diff --git a/backend/model/tag/BUILD b/backend/model/tag/BUILD new file mode 100644 index 0000000000..9487eeab53 --- /dev/null +++ b/backend/model/tag/BUILD @@ -0,0 +1,19 @@ +load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") +load("//tools/build:java_library.bzl", "custom_java_library") + +custom_java_library( + name = "tag", + srcs = glob(["src/main/java/co/airy/model/tag/**/*.java"]), + visibility = ["//visibility:public"], + exports = [ + "//backend/avro:tag-avro", + "//lib/java/kafka/schema:application-communication-tags", + ], + deps = [ + "//:jackson", + "//:lombok", + "//backend/avro:tag-avro", + ], +) + +check_pkg(name = "buildifier") diff --git a/backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java b/backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java new file mode 100644 index 0000000000..4a692c84ac --- /dev/null +++ b/backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java @@ -0,0 +1,25 @@ +package co.airy.core.api.admin.payload; + +import co.airy.avro.communication.Tag; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class TagPayload { + private String id; + private String name; + private String color; + + public static TagPayload fromTag(Tag tag) { + return TagPayload.builder() + .id(tag.getId()) + .color("tag-"+tag.getColor().toString().toLowerCase()) + .name(tag.getName()) + .build(); + } +} diff --git a/docs/docs/api/endpoints/chatplugin.md b/docs/docs/api/endpoints/chatplugin.md index ecefde4b54..5277812e22 100644 --- a/docs/docs/api/endpoints/chatplugin.md +++ b/docs/docs/api/endpoints/chatplugin.md @@ -3,7 +3,7 @@ title: Chat Plugin sidebar_label: Chat Plugin --- -Refer to our [Chat Plugin introduction](sources/chatplugin/overview.md) for +Refer to our [Chat Plugin overview](sources/chatplugin/overview.md) document for more information. The HTTP api adheres to standards laid out in the [core @@ -16,8 +16,9 @@ API](/api/introduction#authentication). The request returns an authentication token that needs to be included in the WebSocket connection handshake. -You can either pass the `channel_id` for a new conversation or a `resume_token` that was obtained in a -previous conversation using the [resume endpoint](#get-a-resume-token). +You can either pass the `channel_id` for a new conversation or a `resume_token` +that was obtained in a previous conversation using the [resume +endpoint](#get-a-resume-token). **Sample request** @@ -75,8 +76,9 @@ endpoint](#authenticating-web-users) as an `Authorization` header. } ``` -You can also obtain a resume token on behalf of the user. To do so you need to call this endpoint with the -system API token set on the `Authorization` header and with the channel and conversation id. +You can also obtain a resume token on behalf of the user. To do so you need to +call this endpoint with the system API token set on the `Authorization` header +and with the channel and conversation id. **Sample request** @@ -89,8 +91,8 @@ system API token set on the `Authorization` header and with the channel and conv #### Send message -You must set the `token` obtained on the [authorization endpoint](#authenticating-web-users) as an `Authorization` -header. +You must set the `token` obtained on the [authorization +endpoint](#authenticating-web-users) as an `Authorization` header. `POST /chatplugin.send` diff --git a/docs/docs/api/endpoints/messages.md b/docs/docs/api/endpoints/messages.md index 340adc2eca..4396634c55 100644 --- a/docs/docs/api/endpoints/messages.md +++ b/docs/docs/api/endpoints/messages.md @@ -3,15 +3,15 @@ title: Messages sidebar_label: Messages --- -Refer to our [messages](getting-started/glossary.md#message) definition -for more information. +Refer to our [message](getting-started/glossary.md#message) definition for more +information. ## List `POST /messages.list` -This is a [paginated](#pagination) endpoint. Messages are sorted from oldest to -latest. +This is a [paginated](api/endpoints/introduction.md#pagination) endpoint. Messages +are sorted from oldest to latest. **Sample request** diff --git a/docs/docs/api/endpoints/metadata.md b/docs/docs/api/endpoints/metadata.md index 6a7e78d53a..3c9fe62a91 100644 --- a/docs/docs/api/endpoints/metadata.md +++ b/docs/docs/api/endpoints/metadata.md @@ -3,12 +3,14 @@ title: Metadata sidebar_label: Metadata --- -Have a look at our [metadata design](concepts/metadata.md) for more information. +Refer to our [metadata design](concepts/metadata.md) document for more +information. ## Upsert -This endpoint takes a `data` object and upserts the metadata for the `id`. The data may only contain -values of type string or object values (i.e. no lists or numbers). +This endpoint takes a `data` object and upserts the metadata for the `id`. The +data may only contain values of type string or object values (i.e. no lists or +numbers). `POST /metadata.upsert` diff --git a/docs/docs/api/endpoints/tags.md b/docs/docs/api/endpoints/tags.md index 82251e761e..7d2244b5fb 100644 --- a/docs/docs/api/endpoints/tags.md +++ b/docs/docs/api/endpoints/tags.md @@ -3,7 +3,7 @@ title: Tags sidebar_label: Tags --- -Please refer to our [tag](getting-started/glossary.md#tag) definition for more +Refer to our [tag](getting-started/glossary.md#tag) definition for more information. ## Create @@ -19,7 +19,8 @@ information. } ``` -If the tag is successfully created, the request returns status code `201` (created) with the tag ID in the response body. +If the tag is successfully created, the request returns status code `201` +(created) with the tag ID in the response body. **Sample response** @@ -45,8 +46,6 @@ If the tag is successfully created, the request returns status code `201` (creat } ``` -If action is successful, the request returns status code `200`. - **Empty response (204)** ## Delete @@ -61,8 +60,6 @@ If action is successful, the request returns status code `200`. } ``` -If action is successful, returns HTTP status `200`. - **Empty response (204)** ## List @@ -77,7 +74,7 @@ If action is successful, returns HTTP status `200`. { "id": "TAG-ID", "name": "name of the tag", - "color": "RED" + "color": "tag-red" } ] } diff --git a/docs/docs/api/websocket.md b/docs/docs/api/websocket.md index 9aa3fc9afb..ffe2080688 100644 --- a/docs/docs/api/websocket.md +++ b/docs/docs/api/websocket.md @@ -18,8 +18,9 @@ protocol endpoint at `/ws.communication`. ## Event Payloads -All event updates are sent to the `/events` queue as JSON encoded payloads. The `type` -field informs the client of the kind of update that is encoded in the payload. +All event updates are sent to the `/events` queue as JSON encoded payloads. The +`type` field informs the client of the kind of update that is encoded in the +payload. ### Message @@ -81,3 +82,17 @@ field informs the client of the kind of update that is encoded in the payload. } } ``` + +### Tag + +```json5 +{ + "type": "tag", + + "payload": { + "id": "{UUID}", + "name": "flag", + "color": "tag-red" + } +} +``` diff --git a/frontend/ui/src/actions/conversations/index.ts b/frontend/ui/src/actions/conversations/index.ts index 6ef760da13..11cd89de3e 100644 --- a/frontend/ui/src/actions/conversations/index.ts +++ b/frontend/ui/src/actions/conversations/index.ts @@ -4,7 +4,7 @@ import {Conversation, Pagination} from 'model'; import {PaginatedResponse} from 'httpclient'; import {HttpClientInstance} from '../../InitializeAiryApi'; import {StateModel} from '../../reducers'; -import {mergeMetadataAction, setMetadataAction} from '../metadata'; +import {setMetadataAction} from '../metadata'; const CONVERSATION_LOADING = '@@conversation/LOADING'; const CONVERSATIONS_LOADING = '@@conversations/LOADING'; @@ -114,7 +114,7 @@ export const conversationState = (conversationId: string, state: string) => (dis export const addTagToConversation = (conversationId: string, tagId: string) => (dispatch: Dispatch) => { HttpClientInstance.tagConversation({conversationId, tagId}).then(() => dispatch( - mergeMetadataAction({ + setMetadataAction({ subject: 'conversation', identifier: conversationId, metadata: { diff --git a/frontend/ui/src/actions/metadata/index.ts b/frontend/ui/src/actions/metadata/index.ts index f221db886e..d8ad43177d 100644 --- a/frontend/ui/src/actions/metadata/index.ts +++ b/frontend/ui/src/actions/metadata/index.ts @@ -1,15 +1,9 @@ import _typesafe, {createAction} from 'typesafe-actions'; import {MetadataEvent} from 'model'; -const MERGE_METADATA = '@@metadata/MERGE_METADATA'; const SET_METADATA = '@@metadata/SET_METADATA'; export const setMetadataAction = createAction( SET_METADATA, (metadataEvent: MetadataEvent) => metadataEvent )(); - -export const mergeMetadataAction = createAction( - MERGE_METADATA, - (metadataEvent: MetadataEvent) => metadataEvent -)(); diff --git a/frontend/ui/src/actions/tags/index.tsx b/frontend/ui/src/actions/tags/index.tsx index 23c0ce2948..5eef58fcff 100644 --- a/frontend/ui/src/actions/tags/index.tsx +++ b/frontend/ui/src/actions/tags/index.tsx @@ -7,23 +7,18 @@ import {HttpClientInstance} from '../../InitializeAiryApi'; const UPSERT_TAG = 'UPSERT_TAG'; const DELETE_TAG = 'DELETE_TAG'; -const EDIT_TAG = 'EDIT_TAG'; const ERROR_TAG = 'ERROR_TAG'; const ADD_TAGS_TO_STORE = 'ADD_TAGS_TO_STORE'; -const SET_TAG_FILTER = 'SET_TAG_FILTER'; export const fetchTagAction = createAction(ADD_TAGS_TO_STORE, (tags: Tag[]) => tags)(); -export const addTagAction = createAction(UPSERT_TAG, (tag: Tag) => tag)(); -export const editTagAction = createAction(EDIT_TAG, (tag: Tag) => tag)(); +export const upsertTagAction = createAction(UPSERT_TAG, (tag: Tag) => tag)(); export const deleteTagAction = createAction(DELETE_TAG, (id: string) => id)(); -export const filterTagAction = createAction(SET_TAG_FILTER, (filter: string) => filter)(); export const errorTagAction = createAction(ERROR_TAG, (status: string) => status)(); export function listTags() { - return function (dispatch: Dispatch) { - return HttpClientInstance.listTags().then((response: Tag[]) => { - dispatch(fetchTagAction(response)); - }); + return async function (dispatch: Dispatch) { + const response = await HttpClientInstance.listTags(); + dispatch(fetchTagAction(response)); }; } @@ -31,7 +26,7 @@ export function createTag(requestPayload: CreateTagRequestPayload) { return async (dispatch: Dispatch) => { return HttpClientInstance.createTag(requestPayload) .then((response: Tag) => { - dispatch(addTagAction(response)); + dispatch(upsertTagAction(response)); return Promise.resolve(response); }) .catch((error: string) => { @@ -43,7 +38,7 @@ export function createTag(requestPayload: CreateTagRequestPayload) { export function updateTag(tag: Tag) { return function (dispatch: Dispatch) { - HttpClientInstance.updateTag(tag).then(() => dispatch(editTagAction(tag))); + HttpClientInstance.updateTag(tag).then(() => dispatch(upsertTagAction(tag))); }; } @@ -55,12 +50,6 @@ export function deleteTag(id: string) { }; } -export function filterTags(filter: string) { - return function (dispatch: Dispatch) { - dispatch(filterTagAction(filter)); - }; -} - export function errorTag(status: string) { return function (dispatch: Dispatch) { dispatch(errorTagAction(status)); diff --git a/frontend/ui/src/components/AiryWebsocket/index.tsx b/frontend/ui/src/components/AiryWebsocket/index.tsx index 5dd73ea2db..d4f890d767 100644 --- a/frontend/ui/src/components/AiryWebsocket/index.tsx +++ b/frontend/ui/src/components/AiryWebsocket/index.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect} from 'react'; import _, {connect, ConnectedProps} from 'react-redux'; import {WebSocketClient} from 'websocketclient'; -import {Message, Channel, MetadataEvent} from 'model'; +import {Message, Channel, MetadataEvent, Tag} from 'model'; import camelcaseKeys from 'camelcase-keys'; import {env} from '../../env'; @@ -11,12 +11,11 @@ import {getConversationInfo} from '../../actions/conversations'; import {setChannelAction} from '../../actions/channel'; import {setMetadataAction} from '../../actions/metadata'; import {allConversations} from '../../selectors/conversations'; +import {upsertTagAction} from '../../actions'; type AiryWebSocketProps = {} & ConnectedProps; -export const AiryWebSocketContext = React.createContext({ - refreshSocket: null, -}); +export const AiryWebSocketContext = React.createContext({refreshSocket: null}); const mapStateToProps = (state: StateModel) => ({ conversations: allConversations(state), @@ -33,12 +32,15 @@ const mapDispatchToProps = dispatch => ({ stopPaths: ['payload.metadata.user_data', 'payload.metadata.tags'], }) ), + onTag: (tag: Tag) => { + dispatch(upsertTagAction(tag)); + }, }); const connector = connect(mapStateToProps, mapDispatchToProps); const AiryWebSocket: React.FC = props => { - const {children, conversations, getConversationInfo, addMessages, onChannel, onMetadata} = props; + const {children, conversations, getConversationInfo, addMessages, onChannel, onMetadata, onTag} = props; const [webSocketClient, setWebSocketClient] = useState(null); const onMessage = (conversationId: string, message: Message) => { @@ -62,6 +64,7 @@ const AiryWebSocket: React.FC = props => { }, onChannel, onMetadata, + onTag, }) ); }; diff --git a/frontend/ui/src/components/ChannelAvatar/index.tsx b/frontend/ui/src/components/ChannelAvatar/index.tsx index 0c78d3d7de..72331a2758 100644 --- a/frontend/ui/src/components/ChannelAvatar/index.tsx +++ b/frontend/ui/src/components/ChannelAvatar/index.tsx @@ -39,7 +39,7 @@ const ChannelAvatar = (props: ChannelAvatarProps) => { return ; case Source.twilioSMS: return ; - case Source.twilioWhatsapp: + case Source.twilioWhatsApp: return ; default: return ; diff --git a/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx b/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx index ce4f62087d..76b7cb646e 100644 --- a/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx +++ b/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx @@ -12,7 +12,6 @@ import styles from './index.module.scss'; type ConnectedChannelsBySourceCardProps = { sourceInfo: SourceInfo; channels: Channel[]; - connected: string; }; const ConnectedChannelsBySourceCard = (props: ConnectedChannelsBySourceCardProps & RouteComponentProps) => { @@ -26,9 +25,7 @@ const ConnectedChannelsBySourceCard = (props: ConnectedChannelsBySourceCardProps <>
-

- {channels.length} {props.connected} -

+

{channels.length} Connected

{ setName('Twilio SMS'); setPath(CHANNELS_TWILIO_SMS_ROUTE + '/new_account'); break; - case Source.twilioWhatsapp: + case Source.twilioWhatsApp: setName('Twilio Whatsapp'); setPath(CHANNELS_TWILIO_WHATSAPP_ROUTE + '/new_account'); break; diff --git a/frontend/ui/src/pages/Channels/MainPage/index.tsx b/frontend/ui/src/pages/Channels/MainPage/index.tsx index baf4f46899..347463bdcb 100644 --- a/frontend/ui/src/pages/Channels/MainPage/index.tsx +++ b/frontend/ui/src/pages/Channels/MainPage/index.tsx @@ -11,7 +11,7 @@ import ConnectedChannelsBySourceCard from '../ConnectedChannelsBySourceCard'; import {ReactComponent as AiryAvatarIcon} from 'assets/images/icons/airy_avatar.svg'; import {ReactComponent as MessengerAvatarIcon} from 'assets/images/icons/messenger_avatar.svg'; import {ReactComponent as SMSAvatarIcon} from 'assets/images/icons/sms_avatar.svg'; -import {ReactComponent as WhatsappLogo} from 'assets/images/icons/whatsapp_avatar.svg'; +import {ReactComponent as WhatsAppAvatarIcon} from 'assets/images/icons/whatsapp_avatar.svg'; import {ReactComponent as GoogleAvatarIcon} from 'assets/images/icons/google_avatar.svg'; import styles from './index.module.scss'; @@ -95,10 +95,10 @@ const SourcesInfo: SourceInfo[] = [ dataCyChannelList: cyChannelsTwilioSmsList, }, { - type: Source.twilioWhatsapp, - title: 'Whatsapp', + type: Source.twilioWhatsApp, + title: 'WhatsApp', description: 'World #1 chat app', - image: , + image: , newChannelRoute: CHANNELS_TWILIO_WHATSAPP_ROUTE + '/new_account', channelsListRoute: CHANNELS_CONNECTED_ROUTE + '/twilio.whatsapp/#', configKey: 'sources-twilio', @@ -133,7 +133,7 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => { case Source.google: return setDisplayDialogFromSource('')} />; case Source.twilioSMS: - case Source.twilioWhatsapp: + case Source.twilioWhatsApp: return setDisplayDialogFromSource('')} />; } @@ -169,11 +169,7 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => { } }} /> - +
))}
diff --git a/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx b/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx index 605a5fc7ee..36ecaa5116 100644 --- a/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx +++ b/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx @@ -52,7 +52,7 @@ const TwilioConnect = (props: TwilioConnectProps) => { imageUrl: imageUrlInput, }; - if (source === Source.twilioWhatsapp) { + if (source === Source.twilioWhatsApp) { connectTwilioWhatsapp(connectPayload).then(() => { history.replace({ pathname: CHANNELS_CONNECTED_ROUTE + `/twilio.whatsapp/#`, diff --git a/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx b/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx index a2e66db9e1..517f46233a 100644 --- a/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx +++ b/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx @@ -43,7 +43,7 @@ const TwilioWhatsappConnect = (props: TwilioWhatsappProps) => { }, [channels, channelId]); return ( - + ); }; diff --git a/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx b/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx index 52255884a3..c7795d48d2 100644 --- a/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx +++ b/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx @@ -1,7 +1,7 @@ import React, {FormEvent, useEffect, useState} from 'react'; import _, {connect, ConnectedProps} from 'react-redux'; import {withRouter} from 'react-router-dom'; -import {Tag as TagModel, TagColor, getTags} from 'model'; +import {Tag as TagModel, TagColor} from 'model'; import {createTag, listTags} from '../../../../actions/tags'; import {addTagToConversation, removeTagFromConversation} from '../../../../actions/conversations'; @@ -17,6 +17,7 @@ import {getCurrentConversation} from '../../../../selectors/conversations'; import {ConversationRouteProps} from '../../index'; import {cyShowTagsDialog, cyTagsDialogInput, cyTagsDialogButton} from 'handles'; +import difference from 'lodash/difference'; const mapStateToProps = (state: StateModel, ownProps: ConversationRouteProps) => { return { @@ -58,31 +59,21 @@ const ConversationMetadata = (props: ConnectedProps) => { removeTagFromConversation(conversation.id, tag.id); }; - const filterForUnusedTags = (tags: TagModel[]): TagModel[] => { - return tags.filter(tag => !(tag.id in (conversation.metadata.tags || {}))); - }; - - const filterForUsedTags = (tags: TagModel[]): TagModel[] => { - return tags.filter(tag => tag.id in (conversation.metadata.tags || {})); - }; + const tagSorter = (a: TagModel, b: TagModel) => a.name.localeCompare(b.name); - const tagSorter = (tagA: TagModel, tagB: TagModel) => { - if (tagA.name < tagB.name) { - return -1; - } - if (tagA.name > tagB.name) { - return 1; - } + const conversationTags = () => + Object.keys(conversation.metadata.tags || {}) + .map(tagId => tags[tagId]) + .filter(tag => tag !== undefined) + .sort(tagSorter); - return 0; - }; - - const checkIfExists = (value: string) => { - const usedTags = filterForUsedTags(tags); - if (value.length == 0) { + const checkIfExists = (tagName: string) => { + const usedTags = conversationTags(); + if (tagName.length === 0) { return true; } - if (usedTags.find(tag => tag.name === value)) { + + if (usedTags.find(tag => tag.name === tagName)) { return 'Tag already added'; } @@ -90,15 +81,17 @@ const ConversationMetadata = (props: ConnectedProps) => { }; const getFilteredTags = (): TagModel[] => - filterForUnusedTags(tags) + difference(Object.keys(tags), Object.keys(conversation.metadata.tags || {})) + .map(id => tags[id]) + .filter(tag => tag !== undefined) .sort(tagSorter) - .filter(tag => tag.name.startsWith(tagName)); + .filter((tag: TagModel) => tag.name.startsWith(tagName)); const submitForm = (event: FormEvent) => { event.preventDefault(); const filteredTags = getFilteredTags(); - if (filteredTags.length == 1) { + if (filteredTags.length === 1) { addTag(filteredTags[0]); } else if (filteredTags.length == 0 && tagName.trim().length > 0) { createTag({name: tagName.trim(), color}).then((tag: TagModel) => { @@ -166,10 +159,6 @@ const ConversationMetadata = (props: ConnectedProps) => { ); }; - const findTag = (tagId: string): TagModel => { - return tags.find(tag => tag.id === tagId); - }; - const contact = conversation.metadata.contact; return (
@@ -179,7 +168,6 @@ const ConversationMetadata = (props: ConnectedProps) => {
-
{contact?.displayName}
@@ -193,11 +181,9 @@ const ConversationMetadata = (props: ConnectedProps) => { {showTagsDialog && renderTagsDialog()}
- {tags && - getTags(conversation) - .map(tagId => findTag(tagId)) - .sort(tagSorter) - .map(tag => tag && removeTag(tag)} />)} + {conversationTags().map(tag => ( + removeTag(tag)} /> + ))}
diff --git a/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx b/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx index f274a14183..77a5bbec7a 100644 --- a/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx +++ b/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx @@ -5,7 +5,7 @@ import {debounce, isEmpty} from 'lodash-es'; import {withRouter} from 'react-router-dom'; import {cyMessageList} from 'handles'; -import {Message, Suggestions, getSource} from 'model'; +import {Message, Suggestions} from 'model'; import {SourceMessage} from 'render'; import {ReactComponent as LightBulbIcon} from 'assets/images/icons/lightbulb.svg'; @@ -179,7 +179,7 @@ const MessageList = (props: MessageListProps) => { lastInGroup={lastInGroup} isChatPlugin={false} decoration={messageDecoration}> - +
); diff --git a/frontend/ui/src/pages/Tags/SimpleTagForm.tsx b/frontend/ui/src/pages/Tags/SimpleTagForm.tsx index 9a70ab9494..c063d496e2 100644 --- a/frontend/ui/src/pages/Tags/SimpleTagForm.tsx +++ b/frontend/ui/src/pages/Tags/SimpleTagForm.tsx @@ -1,8 +1,7 @@ import React, {useState, Fragment} from 'react'; import {connect} from 'react-redux'; -import {createTag, listTags, errorTag, filterTags} from '../../actions/tags'; -import {filteredTags} from '../../selectors/tags'; +import {createTag, listTags, errorTag} from '../../actions/tags'; import {Button, Input} from 'components'; import DialogCustomizable from '../../components/DialogCustomizable'; @@ -98,7 +97,7 @@ const SimpleTagForm = ({errorMessage, createTag, errorTag, onClose, tags}: Simpl const mapStateToProps = (state: StateModel) => { return { - tags: filteredTags(state), + tags: Object.values(state.data.tags.all), errorMessage: state.data.tags.error, }; }; @@ -107,7 +106,6 @@ const mapDispatchToProps = { createTag, errorTag, listTags, - filterTags, }; const connector = connect(mapStateToProps, mapDispatchToProps); diff --git a/frontend/ui/src/pages/Tags/index.tsx b/frontend/ui/src/pages/Tags/index.tsx index 1383a358be..3fbd3da260 100644 --- a/frontend/ui/src/pages/Tags/index.tsx +++ b/frontend/ui/src/pages/Tags/index.tsx @@ -6,10 +6,8 @@ import {cyTagsSearchField, cyTagsTable} from 'handles'; import {ReactComponent as Plus} from 'assets/images/icons/plus.svg'; -import {listTags, deleteTag, filterTags, errorTag} from '../../actions/tags'; -import {filteredTags} from '../../selectors/tags'; +import {listTags, deleteTag, errorTag} from '../../actions/tags'; -import {Tag} from 'model'; import {ModalType} from '../../types'; import {TableRow} from './TableRow'; @@ -30,7 +28,8 @@ const initialState = { delete: '', error: '', }, - tagQuery: '', + query: '', + filteredTags: [], createDrawer: false, emptyState: true, }; @@ -41,14 +40,10 @@ class Tags extends Component, typeof initialSta componentDidMount() { setPageTitle('Tags'); this.props.listTags(); - this.props.filterTags(''); } - handleSearch = (value: string) => { - this.setState({ - tagQuery: value, - }); - this.props.filterTags(value); + handleSearch = (query: string) => { + this.setState({query, filteredTags: this.props.tags.filter(t => t.name.match(query))}); }; handleDelete = (e: React.ChangeEvent) => { @@ -57,7 +52,7 @@ class Tags extends Component, typeof initialSta return { modal: { ...state.modal, - delete: e.target && e.target.value, + delete: e.target?.value, }, }; }); @@ -71,9 +66,7 @@ class Tags extends Component, typeof initialSta }; removeEmptyStateAndCreateTag = () => { - this.setState({ - emptyState: false, - }); + this.setState({emptyState: false}); this.handleTagDrawer(); }; @@ -173,7 +166,7 @@ class Tags extends Component, typeof initialSta }; renderTagList() { - const {tags} = this.props; + const tags = this.state.query !== '' ? this.state.filteredTags : this.props.tags; return (
@@ -184,7 +177,7 @@ class Tags extends Component, typeof initialSta
@@ -202,10 +195,9 @@ class Tags extends Component, typeof initialSta Color - {tags && - tags.map((tag: Tag, idx: number) => { - return ; - })} + {tags.map(tag => ( + + ))} ) : ( @@ -235,18 +227,15 @@ class Tags extends Component, typeof initialSta } const mapStateToProps = (state: StateModel) => ({ - tags: filteredTags(state), - allTagsCount: state.data.tags.all.length, - tagQuery: state.data.tags.query, + tags: Object.values(state.data.tags.all), + allTagsCount: Object.keys(state.data.tags.all).length, errorMessage: state.data.tags.error, - userData: state.data.user, }); const mapDispatchToProps = { listTags, deleteTag, errorTag, - filterTags, }; const connector = connect(mapStateToProps, mapDispatchToProps); diff --git a/frontend/ui/src/reducers/data/conversations/index.ts b/frontend/ui/src/reducers/data/conversations/index.ts index 0fa9d583ab..3b80a85b96 100644 --- a/frontend/ui/src/reducers/data/conversations/index.ts +++ b/frontend/ui/src/reducers/data/conversations/index.ts @@ -8,7 +8,6 @@ import * as metadataActions from '../../../actions/metadata'; import * as actions from '../../../actions/conversations'; import * as filterActions from '../../../actions/conversationsFilter'; import * as messageActions from '../../../actions/messages'; -import {MetadataEvent, ConversationMetadata} from 'model'; type Action = ActionType | ActionType; type FilterAction = ActionType; @@ -58,7 +57,7 @@ export type ConversationsState = { }; function mergeConversations( - oldConversation: {[conversation_id: string]: MergedConversation}, + oldConversation: {[conversationId: string]: MergedConversation}, newConversations: MergedConversation[] ): ConversationMap { newConversations.forEach((conversation: MergedConversation) => { @@ -90,7 +89,7 @@ function mergeConversations( } function mergeFilteredConversations( - oldConversation: {[conversation_id: string]: MergedConversation}, + oldConversation: {[conversationId: string]: MergedConversation}, newConversations: MergedConversation[] ): ConversationMap { newConversations.forEach((conversation: MergedConversation) => { @@ -160,7 +159,7 @@ const removeTagFromConversation = (state: AllConversationsState, conversationId, ...conversation, metadata: { ...conversation.metadata, - tags: pickBy(conversation.metadata?.tags, (value, key) => key !== tagId), + tags: pickBy(conversation.metadata?.tags, (_, key) => key !== tagId), }, }, }, @@ -214,31 +213,6 @@ function allReducer( return state; } - return { - ...state, - items: { - ...state.items, - [action.payload.identifier]: { - id: action.payload.identifier, - ...state.items[action.payload.identifier], - metadata: { - // Ensure that there is always a display name present - ...(action.payload as MetadataEvent).metadata, - state: action.payload.metadata.state || state.items[action.payload.identifier]?.metadata.state || 'OPEN', - contact: { - ...state.items[action.payload.identifier]?.metadata.contact, - ...(action.payload as MetadataEvent).metadata.contact, - }, - }, - }, - }, - }; - - case getType(metadataActions.mergeMetadataAction): - if (action.payload.subject !== 'conversation') { - return state; - } - return { ...state, items: { diff --git a/frontend/ui/src/reducers/data/messages/index.ts b/frontend/ui/src/reducers/data/messages/index.ts index 67a38d05b0..e058bac131 100644 --- a/frontend/ui/src/reducers/data/messages/index.ts +++ b/frontend/ui/src/reducers/data/messages/index.ts @@ -2,7 +2,7 @@ import {ActionType, getType} from 'typesafe-actions'; import * as actions from '../../../actions/messages'; import * as metadataActions from '../../../actions/metadata'; import {Message, MessageMetadata} from 'model'; -import {cloneDeep, merge, sortBy} from 'lodash-es'; +import {cloneDeep, sortBy} from 'lodash-es'; type Action = ActionType | ActionType; @@ -59,29 +59,6 @@ const setMetadata = (state: Messages, action: ActionType }, }; }; -const mergeMetadata = (state: Messages, action: ActionType) => { - const conversationId = findConversationId(state, action.payload.identifier); - - if (conversationId == undefined) { - return state; - } - - return { - ...state, - all: { - ...state.all, - [conversationId]: state.all[conversationId].map((message: Message) => { - if (message.id !== action.payload.identifier) { - return message; - } - return { - ...message, - metadata: merge({}, message.metadata, action.payload.metadata as MessageMetadata), - }; - }), - }, - }; -}; export default function messagesReducer(state = initialState, action: Action): Messages { switch (action.type) { @@ -102,13 +79,6 @@ export default function messagesReducer(state = initialState, action: Action): M return state; } return setMetadata(state, action); - - case getType(metadataActions.mergeMetadataAction): - if (action.payload.subject !== 'conversation') { - return state; - } - return mergeMetadata(state, action); - default: return state; } diff --git a/frontend/ui/src/reducers/data/tags/index.ts b/frontend/ui/src/reducers/data/tags/index.ts index 1c782edb95..8bcc7b198d 100644 --- a/frontend/ui/src/reducers/data/tags/index.ts +++ b/frontend/ui/src/reducers/data/tags/index.ts @@ -1,23 +1,19 @@ import {ActionType, getType} from 'typesafe-actions'; import * as actions from '../../../actions/tags'; import {Tag} from 'model'; -import {DataState} from '../../data'; +import {omit, keyBy} from 'lodash'; type Action = ActionType; -export type TagState = { - data: DataState; -}; - export type Tags = { - all: Tag[]; - query: string; + all: { + [tagId: string]: Tag; + }; error: string; }; const defaultState = { - all: [], - query: '', + all: {}, error: '', }; @@ -40,46 +36,27 @@ export default function tagsReducer(state = defaultState, action: Action): any { case getType(actions.fetchTagAction): return { ...state, - all: action.payload, + all: keyBy(action.payload, 'id'), }; case getType(actions.deleteTagAction): return { ...state, - all: state.all.filter((tag: Tag) => tag.id !== action.payload), + all: omit(state.all, action.payload), }; - case getType(actions.addTagAction): { - let updatedTag = false; - const mappedTags = state.all.map((tag: Tag) => { - if (tag.id === action.payload.id) { - updatedTag = true; - return { - ...tag, - ...action.payload, - }; - } - return tag; - }); - + case getType(actions.upsertTagAction): { return { ...state, - all: updatedTag ? mappedTags : state.all.concat([action.payload]), + all: { + ...state.all, + [action.payload.id]: action.payload, + }, }; } - case getType(actions.editTagAction): - return { - ...state, - all: state.all.map((tag: Tag) => (tag.id === action.payload.id ? action.payload : tag)), - }; case getType(actions.errorTagAction): return { ...state, error: errorMessage(action.payload), }; - case getType(actions.filterTagAction): - return { - ...state, - query: action.payload, - }; default: return state; } diff --git a/frontend/ui/src/selectors/tags.ts b/frontend/ui/src/selectors/tags.ts deleted file mode 100644 index 8e492ed972..0000000000 --- a/frontend/ui/src/selectors/tags.ts +++ /dev/null @@ -1,21 +0,0 @@ -import _redux from 'redux'; -import _, {createSelector} from 'reselect'; -import {Tag} from 'model'; -import {StateModel} from '../reducers'; - -const tags = (state: StateModel) => state.data.tags.all; -const queries = (state: StateModel) => state.data.tags.query; -const filter = (tags: Tag[], filter: string) => { - if (filter === '') { - return tags; - } - return ( - filter && - filter.length && - tags.filter((tag: Tag) => { - return tag.name.toLowerCase().includes(filter.toLowerCase()); - }) - ); -}; - -export const filteredTags = createSelector(tags, queries, filter); diff --git a/lib/typescript/httpclient/README.md b/lib/typescript/httpclient/README.md index 9049c8020c..74fc538242 100644 --- a/lib/typescript/httpclient/README.md +++ b/lib/typescript/httpclient/README.md @@ -2,7 +2,8 @@ The HttpClient Library includes a HTTP client for making requests to Airy's API. -The library exports a HttpClient class with public methods that make requests to Airy's API. +The library exports a HttpClient class with public methods that make requests to +Airy's API. To use the library, you need to instantiate the class with an Airy Core API URL. @@ -14,34 +15,3 @@ import {HttpClient} from "httpclient"; const client = new HttpClient("http://airy.core"); client.listChannels().then(channels => console.debug("channels", channels)); ``` - -Here is a list of the public methods the library's class includes: - -CHANNELS - -- listChannels -- exploreChannels -- connectChannel -- disconnectChannel -- connectFacebookChannel -- exploreFacebookChannels - -CONVERSATIONS - -- listConversations -- getConversationInfo -- readConversations -- tagConversation -- untagConversation - -MESSAGES - -- listMessages -- sendMessages - -TAGS - -- listTags -- createTag -- updateTag -- deleteTag diff --git a/lib/typescript/httpclient/src/endpoints/createTag.ts b/lib/typescript/httpclient/src/endpoints/createTag.ts index 6306f1e181..b0d4595698 100644 --- a/lib/typescript/httpclient/src/endpoints/createTag.ts +++ b/lib/typescript/httpclient/src/endpoints/createTag.ts @@ -1,17 +1,3 @@ -import {Tag} from 'model'; - -const tagMapper = { - BLUE: 'tag-blue', - RED: 'tag-red', - GREEN: 'tag-green', - PURPLE: 'tag-purple', -}; - export const createTagDef = { endpoint: 'tags.create', - mapResponse: (response: Tag) => ({ - id: response.id, - name: response.name, - color: tagMapper[response.color] || 'tag-blue', - }), }; diff --git a/lib/typescript/httpclient/src/endpoints/deleteTag.ts b/lib/typescript/httpclient/src/endpoints/deleteTag.ts index 219638ff75..afcb26f045 100644 --- a/lib/typescript/httpclient/src/endpoints/deleteTag.ts +++ b/lib/typescript/httpclient/src/endpoints/deleteTag.ts @@ -1,5 +1,4 @@ export const deleteTagDef = { endpoint: 'tags.delete', mapRequest: id => ({id}), - mapResponse: response => response, }; diff --git a/lib/typescript/httpclient/src/endpoints/listTags.ts b/lib/typescript/httpclient/src/endpoints/listTags.ts index a839a5e76b..095bba761e 100644 --- a/lib/typescript/httpclient/src/endpoints/listTags.ts +++ b/lib/typescript/httpclient/src/endpoints/listTags.ts @@ -1,14 +1,4 @@ -import {Tag} from 'model'; - -const tagMapper = { - BLUE: 'tag-blue', - RED: 'tag-red', - GREEN: 'tag-green', - PURPLE: 'tag-purple', -}; - export const listTagsDef = { endpoint: 'tags.list', - mapResponse: response => - response.data.map((t: Tag) => ({id: t.id, name: t.name, color: tagMapper[t.color] || 'tag-blue'})), + mapResponse: response => response.data, }; diff --git a/lib/typescript/model/Conversation.ts b/lib/typescript/model/Conversation.ts index 8f7d1f52bf..93a9b8f918 100644 --- a/lib/typescript/model/Conversation.ts +++ b/lib/typescript/model/Conversation.ts @@ -19,11 +19,3 @@ export interface Conversation { createdAt: Date; lastMessage: Message; } - -export function getTags(conversation: Conversation) { - return Object.keys(conversation.metadata.tags || {}); -} - -export function getSource(conversation: Conversation) { - return conversation?.channel?.source; -} diff --git a/lib/typescript/model/Source.ts b/lib/typescript/model/Source.ts index 34bb6d5203..33bb5573b1 100644 --- a/lib/typescript/model/Source.ts +++ b/lib/typescript/model/Source.ts @@ -3,5 +3,5 @@ export enum Source { google = 'google', chatPlugin = 'chatplugin', twilioSMS = 'twilio.sms', - twilioWhatsapp = 'twilio.whatsapp', + twilioWhatsApp = 'twilio.whatsapp', } diff --git a/lib/typescript/websocketclient/index.ts b/lib/typescript/websocketclient/index.ts index 3de16c780c..b40da9ff51 100644 --- a/lib/typescript/websocketclient/index.ts +++ b/lib/typescript/websocketclient/index.ts @@ -1,6 +1,6 @@ import {StompWrapper} from './stompWrapper'; -import {Message, Channel, MetadataEvent} from 'model'; -import {EventPayloadUnion} from './payload'; +import {Message, Channel, MetadataEvent, Tag} from 'model'; +import {EventPayload} from './payload'; /* eslint-disable @typescript-eslint/no-var-requires */ const camelcaseKeys = require('camelcase-keys'); @@ -8,6 +8,7 @@ type CallbackMap = { onMessage?: (conversationId: string, channelId: string, message: Message) => void; onMetadata?: (metadataEvent: MetadataEvent) => void; onChannel?: (channel: Channel) => void; + onTag?: (tag: Tag) => void; onError?: () => void; }; @@ -41,7 +42,7 @@ export class WebSocketClient { }; onEvent = (body: string) => { - const json: EventPayloadUnion = JSON.parse(body) as any; + const json = JSON.parse(body) as EventPayload; switch (json.type) { case 'channel': this.callbackMap.onChannel?.(camelcaseKeys(json.payload, {deep: true, stopPaths: ['metadata.user_data']})); @@ -55,6 +56,9 @@ export class WebSocketClient { case 'metadata': this.callbackMap.onMetadata?.(json.payload); break; + case 'tag': + this.callbackMap.onTag?.(json.payload); + break; default: console.error('Unknown /events payload', json); } diff --git a/lib/typescript/websocketclient/payload.ts b/lib/typescript/websocketclient/payload.ts index 18c989b329..e02c44e46c 100644 --- a/lib/typescript/websocketclient/payload.ts +++ b/lib/typescript/websocketclient/payload.ts @@ -1,27 +1,7 @@ -import {DeliveryState, Metadata, MetadataEvent} from 'model'; +import {DeliveryState, Metadata, MetadataEvent, Tag} from 'model'; interface Event { - type: 'message' | 'channel' | 'metadata'; -} - -interface MessagePayload { - id: string; - content: string; - delivery_state: DeliveryState; - from_contact: boolean; - sent_at: Date; - metadata: any; -} - -interface ChannelPayload { - id: string; - metadata?: Metadata & { - name: string; - image_url?: string; - }; - source: string; - source_channel_id: string; - connected: boolean; + type: 'message' | 'channel' | 'metadata' | 'tag'; } export interface MessageEventPayload extends Event { @@ -29,13 +9,28 @@ export interface MessageEventPayload extends Event { payload: { conversation_id: string; channel_id: string; - message: MessagePayload; + message: { + id: string; + content: string; + delivery_state: DeliveryState; + from_contact: boolean; + sent_at: Date; + }; }; } export interface ChannelEventPayload extends Event { type: 'channel'; - payload: ChannelPayload; + payload: { + id: string; + metadata?: Metadata & { + name: string; + image_url?: string; + }; + source: string; + source_channel_id: string; + connected: boolean; + }; } export interface MetadataEventPayload extends Event { @@ -43,4 +38,9 @@ export interface MetadataEventPayload extends Event { payload: MetadataEvent; } -export type EventPayloadUnion = MessageEventPayload | ChannelEventPayload | MetadataEventPayload; +export interface TagEventPayload extends Event { + type: 'tag'; + payload: Tag; +} + +export type EventPayload = MessageEventPayload | ChannelEventPayload | MetadataEventPayload | TagEventPayload; From 6a13489dc594abd1493d34059cc2fd089c3435d1 Mon Sep 17 00:00:00 2001 From: Aitor Algorta Date: Thu, 29 Apr 2021 12:56:28 +0200 Subject: [PATCH 14/28] [#1674] Chatplugin customize problems (#1678) * fixed shadow problem * reset config * linting --- frontend/chat-plugin/src/App.tsx | 14 +---- .../src/components/chat/index.module.scss | 23 +++++++- .../chat-plugin/src/components/chat/index.tsx | 56 +++++++++++-------- .../ChatPlugin/sections/CustomiseSection.tsx | 18 +++--- 4 files changed, 64 insertions(+), 47 deletions(-) diff --git a/frontend/chat-plugin/src/App.tsx b/frontend/chat-plugin/src/App.tsx index b88ea86e79..c125e3a9a7 100644 --- a/frontend/chat-plugin/src/App.tsx +++ b/frontend/chat-plugin/src/App.tsx @@ -17,22 +17,10 @@ export default class App extends Component { const queryParams = new URLSearchParams(window.location.search); const channelId = queryParams.get('channel_id'); - const customStyle = { - background: 'transparent', - ...(config?.primaryColor && { - '--color-airy-blue': config?.primaryColor, - }), - ...(config?.accentColor && { - '--color-airy-accent': config?.accentColor, - '--color-airy-blue-hover': config?.accentColor, - '--color-airy-blue-pressed': config?.accentColor, - }), - }; - const apiHost: string = window.airy ? window.airy.host : process.env.API_HOST; return ( -
+
{channelId ? ( { defaultWelcomeMessage.content = config.welcomeMessage; } + const customStyle = { + background: 'transparent', + ...(config?.primaryColor && { + '--color-airy-blue': config?.primaryColor, + }), + ...(config?.accentColor && { + '--color-airy-accent': config?.accentColor, + '--color-airy-blue-hover': config?.accentColor, + '--color-airy-blue-pressed': config?.accentColor, + }), + }; + const chatHiddenInitialState = (): boolean => { if (config.showMode === true) return false; if (getResumeTokenFromStorage(props.channelId)) return true; @@ -205,7 +216,7 @@ const Chat = (props: Props) => { }; return ( -
+
{!isChatHidden && (
{
{connectionState === ConnectionState.Disconnected && ( -
Reconnecting...
+
Reconnecting...
+ )} + {showModal && ( +
+
+

Are you sure you want to end this chat?

+
+ + +
+
+
)}
)} - {showModal && ( - - <> -
- - -
- -
- )}
); }; diff --git a/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx b/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx index 87eb23a7fd..f578c87ff8 100644 --- a/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx +++ b/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx @@ -54,13 +54,13 @@ export const CustomiseSection = ({channelId, host}: CustomiseSectionProps) => { return ''; } let config = ''; - if (headerText !== '') config += `\n headerText: '${headerText}'`; - if (bubbleIconUrl !== '') config += `\n bubbleIcon: '${bubbleIconUrl}'`; - if (sendMessageIconUrl !== '') config += `\n sendMessageIcon: '${sendMessageIconUrl}'`; - if (headerTextColor !== '') config += `\n headerTextColor: '${headerTextColor}'`; - if (primaryColor !== '') config += `\n primaryColor: '${primaryColor}'`; - if (accentColor !== '') config += `\n accentColor: '${accentColor}'`; - if (backgroundColor !== '') config += `\n backgroundColor: '${backgroundColor}'`; + if (headerText !== '') config += `\n headerText: '${headerText}',`; + if (bubbleIconUrl !== '') config += `\n bubbleIcon: '${bubbleIconUrl}',`; + if (sendMessageIconUrl !== '') config += `\n sendMessageIcon: '${sendMessageIconUrl}',`; + if (headerTextColor !== '') config += `\n headerTextColor: '${headerTextColor}',`; + if (primaryColor !== '') config += `\n primaryColor: '${primaryColor}',`; + if (accentColor !== '') config += `\n accentColor: '${accentColor}',`; + if (backgroundColor !== '') config += `\n backgroundColor: '${backgroundColor}',`; return ` w[n].config = {${config} @@ -94,9 +94,9 @@ export const CustomiseSection = ({channelId, host}: CustomiseSectionProps) => { w[n].channelId = "${channelId}"; w[n].host = "${host}";${getTemplateConfig()} var f = d.getElementsByTagName(s)[0], - j = d.createElement(s); + j = d.createElement(s); j.async = true; - j.src = w[n].host + "/s.js"; + j.src = w[n].host + '/chatplugin/ui/s.js'; f.parentNode.insertBefore(j, f); })(window, document, "script", "airy"); `; From e395ec0d132a5fbd4d37b2dce084587bceb44dbb Mon Sep 17 00:00:00 2001 From: AudreyKj <38159391+AudreyKj@users.noreply.github.com> Date: Thu, 29 Apr 2021 13:34:08 +0200 Subject: [PATCH 15/28] [#1652] Fix rendering messages with render library (#1675) * fixed suggestion response inbound from google * removed log and linting --- lib/typescript/render/providers/google/GoogleRender.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/typescript/render/providers/google/GoogleRender.tsx b/lib/typescript/render/providers/google/GoogleRender.tsx index 87e7ff91cc..599371c331 100644 --- a/lib/typescript/render/providers/google/GoogleRender.tsx +++ b/lib/typescript/render/providers/google/GoogleRender.tsx @@ -51,7 +51,7 @@ function render(content: ContentUnion, props: RenderPropsUnion) { } function googleInbound(message: Message): ContentUnion { - const messageJson = message.content.message; + const messageJson = message.content.message ?? message.content; if (messageJson.richCard?.standaloneCard) { const { From 1fe6d56e0f23d9d64eaeb2f375d3379c7bb3236c Mon Sep 17 00:00:00 2001 From: AudreyKj <38159391+AudreyKj@users.noreply.github.com> Date: Thu, 29 Apr 2021 13:34:40 +0200 Subject: [PATCH 16/28] [#1676] fix sending messages to google source (#1677) * fix sending messages to google source * fixed response --- .../api/endpoints/google-messages-send.mdx | 32 ++++++++++--------- docs/docs/sources/google.md | 4 +-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/docs/api/endpoints/google-messages-send.mdx b/docs/docs/api/endpoints/google-messages-send.mdx index cd306095dd..1ddfa30ca7 100644 --- a/docs/docs/api/endpoints/google-messages-send.mdx +++ b/docs/docs/api/endpoints/google-messages-send.mdx @@ -11,13 +11,11 @@ Whatever is put on the `message` field will be forwarded "as-is" to the source's ```json5 { - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "message": { - "text": "Hello World Agent!", - "representative": { - "displayName": "Hello World from Agent", - "avatarImage": "REPRESENTATIVE_AVATAR_URL", - "representativeType": "HUMAN", + conversation_id: 'a688d36c-a85e-44af-bc02-4248c2c97622', + message: { + text: 'Hello!', + representative: { + representativeType: 'HUMAN', }, }, } @@ -27,17 +25,21 @@ Whatever is put on the `message` field will be forwarded "as-is" to the source's ```json5 { - "id": "{UUID}", - "content": "{\"text\":\"Hello\"}", - "state": "pending|failed|delivered", - "from_contact": true, + "id": '{UUID}', + "content": { + "text": 'Hello!', + "representative": { + "representativeType": 'HUMAN', + }, + }, + "delivery_state": 'pending|failed|delivered', + "from_contact": 'true|false', // See glossary - "sent_at": "{string}", + "sent_at": '{string}', //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients - "source": "{String}", - // one of the possible sources + "source": 'google', "metadata": { - "sentFrom": "iPhone", + "sentFrom": 'iPhone', }, // metadata object of the message } diff --git a/docs/docs/sources/google.md b/docs/docs/sources/google.md index c432f85826..8c8750db71 100644 --- a/docs/docs/sources/google.md +++ b/docs/docs/sources/google.md @@ -92,6 +92,6 @@ import ConnectGoogle from '../api/endpoints/connect-google.mdx' After connecting the source to your instance, you will be able to send messages through the [Messages endpoint](/api/endpoints/messages#send). -import InboxMessages from './inbox-messages.mdx' +import GoogleMessagesSend from '../api/endpoints/google-messages-send.mdx' - + From 83ca4adb7f772fb9ddfaf17cbfd345e4154cc6c9 Mon Sep 17 00:00:00 2001 From: AudreyKj <38159391+AudreyKj@users.noreply.github.com> Date: Thu, 29 Apr 2021 15:16:32 +0200 Subject: [PATCH 17/28] [#1646] fix avatar images styling (#1680) --- .../render/components/Avatar/index.module.scss | 6 +----- lib/typescript/render/components/Avatar/index.tsx | 14 ++++++-------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/typescript/render/components/Avatar/index.module.scss b/lib/typescript/render/components/Avatar/index.module.scss index 0645713cd9..5dc1dba968 100644 --- a/lib/typescript/render/components/Avatar/index.module.scss +++ b/lib/typescript/render/components/Avatar/index.module.scss @@ -1,13 +1,9 @@ @import 'assets/scss/fonts.scss'; @import 'assets/scss/colors.scss'; -.avatar { - display: flex; - flex-shrink: 0; -} - .avatarImage { border-radius: 50%; width: 100%; height: 100%; + object-fit: cover; } diff --git a/lib/typescript/render/components/Avatar/index.tsx b/lib/typescript/render/components/Avatar/index.tsx index c51441e03f..33f18f7b28 100644 --- a/lib/typescript/render/components/Avatar/index.tsx +++ b/lib/typescript/render/components/Avatar/index.tsx @@ -14,12 +14,10 @@ const fallbackAvatarImage = (event: SyntheticEvent) => }; export const Avatar = ({contact}: AvatarProps) => ( -
- {contact?.displayName) => fallbackAvatarImage(event)} - /> -
+ {contact?.displayName) => fallbackAvatarImage(event)} + /> ); From b3baf24f68f513664938733903c6f97cdcb1eaf1 Mon Sep 17 00:00:00 2001 From: Aitor Algorta Date: Thu, 29 Apr 2021 16:53:18 +0200 Subject: [PATCH 18/28] [#1665] Fix chatplugin reconnection problem (#1682) * fix reconnection problem * remove unnecessary code * linting --- .../src/airyRenderProps/AiryBubble/index.module.scss | 1 + frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.tsx | 2 -- frontend/chat-plugin/src/websocket/index.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.module.scss b/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.module.scss index c3780e8b85..f9b944f10f 100644 --- a/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.module.scss +++ b/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.module.scss @@ -29,6 +29,7 @@ border-left: 8px solid transparent; border-right: 14px solid transparent; cursor: pointer; + z-index: -1; } .hideBubbleCross { diff --git a/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.tsx b/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.tsx index 748aadf333..d0ba0fcdeb 100644 --- a/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.tsx +++ b/frontend/chat-plugin/src/airyRenderProps/AiryBubble/index.tsx @@ -17,11 +17,9 @@ const AiryBubble = (props: Props) => { return ( diff --git a/frontend/chat-plugin/src/websocket/index.ts b/frontend/chat-plugin/src/websocket/index.ts index 09d3e97ed9..ef23337d07 100644 --- a/frontend/chat-plugin/src/websocket/index.ts +++ b/frontend/chat-plugin/src/websocket/index.ts @@ -100,7 +100,6 @@ class WebSocket { reconnect = () => { if (!this.isConnected) { - this.reconnectTimeout = window.setTimeout(this.reconnect, 5000); this.start(); } }; From 3ef466d1ac39529b96cfb1724ce61fe06e48e063 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Apr 2021 10:08:14 +0200 Subject: [PATCH 19/28] Bump @babel/preset-env from 7.13.15 to 7.14.0 (#1684) Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.13.15 to 7.14.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.14.0/packages/babel-preset-env) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 196 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 143 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index fe6a8a043a..bbdfddd828 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-object-rest-spread": "^7.13.8", "@babel/plugin-transform-spread": "^7.13.0", - "@babel/preset-env": "^7.13.15", + "@babel/preset-env": "^7.14.0", "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", "@bazel/bazelisk": "^1.8.0", diff --git a/yarn.lock b/yarn.lock index e2843a0cfd..6c4cf9726c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,10 +16,10 @@ dependencies: "@babel/highlight" "^7.12.13" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4" - integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8", "@babel/compat-data@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" + integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== "@babel/core@7.13.16", "@babel/core@^7.12.3": version "7.13.16" @@ -51,6 +51,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.0.tgz#0f35d663506c43e4f10898fbda0d752ec75494be" + integrity sha512-C6u00HbmsrNPug6A+CiNl8rEys7TsdcXwg12BHi2ca5rUfAs3+UwZsuDQSXnc+wCElCXMB8gMaJ3YXDdh8fAlg== + dependencies: + "@babel/types" "^7.14.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" @@ -66,7 +75,7 @@ "@babel/helper-explode-assignable-expression" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.13.8": +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.13.8": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== @@ -87,6 +96,18 @@ "@babel/helper-replace-supers" "^7.13.0" "@babel/helper-split-export-declaration" "^7.12.13" +"@babel/helper-create-class-features-plugin@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.0.tgz#38367d3dab125b12f94273de418f4df23a11a15e" + integrity sha512-6pXDPguA5zC40Y8oI5mqr+jEUpjMJonKvknvA+vD8CYDz5uuXEwWBK8sRAsE/t3gfb1k15AQb9RhwpscC4nUJQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-create-regexp-features-plugin@^7.12.13": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7" @@ -182,6 +203,20 @@ "@babel/traverse" "^7.13.13" "@babel/types" "^7.13.14" +"@babel/helper-module-transforms@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.0.tgz#8fcf78be220156f22633ee204ea81f73f826a8ad" + integrity sha512-L40t9bxIuGOfpIGA3HNkJhU9qYrf4y5A5LUSw7rGMSn+pcG8dfJ0g6Zval6YJGd2nEjI7oP00fRdnhLKndx6bw== + dependencies: + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-simple-access" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-validator-identifier" "^7.14.0" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" + "@babel/helper-optimise-call-expression@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" @@ -223,13 +258,6 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.12" -"@babel/helper-simple-access@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz#8478bcc5cacf6aa1672b251c1d2dde5ccd61a6c4" - integrity sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-simple-access@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" @@ -256,6 +284,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" @@ -294,6 +327,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== +"@babel/parser@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.0.tgz#2f0ebfed92bcddcc8395b91f1895191ce2760380" + integrity sha512-AHbfoxesfBALg33idaTBVUkLnfXtsgvJREf93p4p0Lwsz4ppfE7g1tpEXVm4vrxUcH4DVhAa9Z1m1zqf9WUC7Q== + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a" @@ -320,6 +358,14 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-class-static-block@^7.13.11": + version "7.13.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.13.11.tgz#6fcbba4a962702c17e5371a0c7b39afde186d703" + integrity sha512-fJTdFI4bfnMjvxJyNuaf8i9mVcZ0UhetaGEUHaHV9KEnibLugJkZAtXikR8KcYj+NYmI4DZMS8yQAyg+hvfSqg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-class-static-block" "^7.12.13" + "@babel/plugin-proposal-dynamic-import@^7.13.8": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz#876a1f6966e1dec332e8c9451afda3bebcdf2e1d" @@ -404,6 +450,16 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-private-property-in-object@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.0.tgz#b1a1f2030586b9d3489cc26179d2eb5883277636" + integrity sha512-59ANdmEwwRUkLjB7CRtwJxxwtjESw+X2IePItA+RGQh+oy5RmpCh/EvVVvh5XQc3yxsm5gtv0+i9oBZhaDNVTg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-create-class-features-plugin" "^7.14.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-private-property-in-object" "^7.14.0" + "@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" @@ -426,6 +482,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-class-static-block@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.12.13.tgz#8e3d674b0613e67975ceac2776c97b60cafc5c9c" + integrity sha512-ZmKQ0ZXR0nYpHZIIuj9zE7oIqCx2hw9TKi+lIo73NNrMPAZGHfS92/VRV0ZmPj6H2ffBgyFHXvJ5NYsNeEaP2A== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" @@ -496,6 +559,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-private-property-in-object@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.0.tgz#762a4babec61176fec6c88480dec40372b140c0b" + integrity sha512-bda3xF8wGl5/5btF794utNOL0Jw+9jE5C1sLZcoK7c4uonE/y3iQiyG+KbkF3WBV/paX58VCpjhxLPkdj5Fe4w== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-top-level-await@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" @@ -533,12 +603,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-block-scoping@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61" - integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ== +"@babel/plugin-transform-block-scoping@^7.13.16": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.13.16.tgz#a9c0f10794855c63b1d629914c7dcfeddd185892" + integrity sha512-ad3PHUxGnfWF4Efd3qFuznEtZKoBp0spS+DgqzVzRPV7urEBvPLue3y2j80w4Jf2YLzZHj8TOv/Lmvdmh3b2xg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-transform-classes@^7.13.0": version "7.13.0" @@ -560,10 +630,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-destructuring@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963" - integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA== +"@babel/plugin-transform-destructuring@^7.13.17": + version "7.13.17" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" + integrity sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA== dependencies: "@babel/helper-plugin-utils" "^7.13.0" @@ -619,23 +689,23 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-modules-amd@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz#19f511d60e3d8753cc5a6d4e775d3a5184866cc3" - integrity sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ== +"@babel/plugin-transform-modules-amd@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.0.tgz#589494b5b290ff76cf7f59c798011f6d77026553" + integrity sha512-CF4c5LX4LQ03LebQxJ5JZes2OYjzBuk1TdiF7cG7d5dK4lAdw9NZmaxq5K/mouUdNeqwz3TNjnW6v01UqUNgpQ== dependencies: - "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.13.8": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz#7b01ad7c2dcf2275b06fa1781e00d13d420b3e1b" - integrity sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw== +"@babel/plugin-transform-modules-commonjs@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" + integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== dependencies: - "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-simple-access" "^7.12.13" + "@babel/helper-simple-access" "^7.13.12" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.13.8": @@ -649,12 +719,12 @@ "@babel/helper-validator-identifier" "^7.12.11" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz#8a3d96a97d199705b9fd021580082af81c06e70b" - integrity sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw== +"@babel/plugin-transform-modules-umd@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" + integrity sha512-nPZdnWtXXeY7I87UZr9VlsWme3Y0cfFFE41Wbxz4bbaexAjNMInXPFUpRRUJ8NoMm0Cw+zxbqjdPmLhcjfazMw== dependencies: - "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-transform-named-capturing-groups-regex@^7.12.13": @@ -818,18 +888,19 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" -"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.15.tgz#c8a6eb584f96ecba183d3d414a83553a599f478f" - integrity sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA== +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.0.tgz#236f88cd5da625e625dd40500d4824523f50e6c5" + integrity sha512-GWRCdBv2whxqqaSi7bo/BEXf070G/fWFMEdCnmoRg2CZJy4GK06ovFuEjJrZhDRXYgBsYtxVbG8GUHvw+UWBkQ== dependencies: - "@babel/compat-data" "^7.13.15" - "@babel/helper-compilation-targets" "^7.13.13" + "@babel/compat-data" "^7.14.0" + "@babel/helper-compilation-targets" "^7.13.16" "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-validator-option" "^7.12.17" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12" "@babel/plugin-proposal-async-generator-functions" "^7.13.15" "@babel/plugin-proposal-class-properties" "^7.13.0" + "@babel/plugin-proposal-class-static-block" "^7.13.11" "@babel/plugin-proposal-dynamic-import" "^7.13.8" "@babel/plugin-proposal-export-namespace-from" "^7.12.13" "@babel/plugin-proposal-json-strings" "^7.13.8" @@ -840,9 +911,11 @@ "@babel/plugin-proposal-optional-catch-binding" "^7.13.8" "@babel/plugin-proposal-optional-chaining" "^7.13.12" "@babel/plugin-proposal-private-methods" "^7.13.0" + "@babel/plugin-proposal-private-property-in-object" "^7.14.0" "@babel/plugin-proposal-unicode-property-regex" "^7.12.13" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.12.13" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" @@ -852,14 +925,15 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.0" "@babel/plugin-syntax-top-level-await" "^7.12.13" "@babel/plugin-transform-arrow-functions" "^7.13.0" "@babel/plugin-transform-async-to-generator" "^7.13.0" "@babel/plugin-transform-block-scoped-functions" "^7.12.13" - "@babel/plugin-transform-block-scoping" "^7.12.13" + "@babel/plugin-transform-block-scoping" "^7.13.16" "@babel/plugin-transform-classes" "^7.13.0" "@babel/plugin-transform-computed-properties" "^7.13.0" - "@babel/plugin-transform-destructuring" "^7.13.0" + "@babel/plugin-transform-destructuring" "^7.13.17" "@babel/plugin-transform-dotall-regex" "^7.12.13" "@babel/plugin-transform-duplicate-keys" "^7.12.13" "@babel/plugin-transform-exponentiation-operator" "^7.12.13" @@ -867,10 +941,10 @@ "@babel/plugin-transform-function-name" "^7.12.13" "@babel/plugin-transform-literals" "^7.12.13" "@babel/plugin-transform-member-expression-literals" "^7.12.13" - "@babel/plugin-transform-modules-amd" "^7.13.0" - "@babel/plugin-transform-modules-commonjs" "^7.13.8" + "@babel/plugin-transform-modules-amd" "^7.14.0" + "@babel/plugin-transform-modules-commonjs" "^7.14.0" "@babel/plugin-transform-modules-systemjs" "^7.13.8" - "@babel/plugin-transform-modules-umd" "^7.13.0" + "@babel/plugin-transform-modules-umd" "^7.14.0" "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.13" "@babel/plugin-transform-new-target" "^7.12.13" "@babel/plugin-transform-object-super" "^7.12.13" @@ -886,7 +960,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.12.13" "@babel/plugin-transform-unicode-regex" "^7.12.13" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.13.14" + "@babel/types" "^7.14.0" babel-plugin-polyfill-corejs2 "^0.2.0" babel-plugin-polyfill-corejs3 "^0.2.0" babel-plugin-polyfill-regenerator "^0.2.0" @@ -966,12 +1040,26 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.4.4": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.16.tgz#916120b858aa5655cfba84bd0f6021ff5bdb4e65" - integrity sha512-7enM8Wxhrl1hB1+k6+xO6RmxpNkaveRWkdpyii8DkrLWRgr0l3x29/SEuhTIkP+ynHsU/Hpjn8Evd/axv/ll6Q== +"@babel/traverse@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.0.tgz#cea0dc8ae7e2b1dec65f512f39f3483e8cc95aef" + integrity sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.14.0" + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/parser" "^7.14.0" + "@babel/types" "^7.14.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.4.4": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.0.tgz#3fc3fc74e0cdad878182e5f66cc6bcab1915a802" + integrity sha512-O2LVLdcnWplaGxiPBz12d0HcdN8QdxdsWYhz5LSeuukV/5mn2xUUc3gBeU4QBYPJ18g/UToe8F532XJ608prmg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" "@bazel/bazelisk@^1.8.0": From dc0f8c2261e7711034fdd57fd4d794fe8fd065a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Apr 2021 13:41:14 +0200 Subject: [PATCH 20/28] Bump @babel/core from 7.13.16 to 7.14.0 (#1685) Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.13.16 to 7.14.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.14.0/packages/babel-core) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 82 +++++++++++++--------------------------------------- 2 files changed, 21 insertions(+), 63 deletions(-) diff --git a/package.json b/package.json index bbdfddd828..14326e08b6 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "typesafe-actions": "^5.1.0" }, "devDependencies": { - "@babel/core": "7.13.16", + "@babel/core": "7.14.0", "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-object-rest-spread": "^7.13.8", "@babel/plugin-transform-spread": "^7.13.0", diff --git a/yarn.lock b/yarn.lock index 6c4cf9726c..f04622c655 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21,20 +21,20 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== -"@babel/core@7.13.16", "@babel/core@^7.12.3": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.16.tgz#7756ab24396cc9675f1c3fcd5b79fcce192ea96a" - integrity sha512-sXHpixBiWWFti0AV2Zq7avpTasr6sIAu7Y396c608541qAU2ui4a193m0KSQmfPSKFZLnQ3cvlKDOm3XkuXm3Q== +"@babel/core@7.14.0", "@babel/core@^7.12.3": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.0.tgz#47299ff3ec8d111b493f1a9d04bf88c04e728d88" + integrity sha512-8YqpRig5NmIHlMLw09zMlPTvUVMILjqCOtVgu+TVNWEBvy9b5I3RRyhqnrV4hjgEK7n8P9OqvkWJAFmEL6Wwfw== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.16" + "@babel/generator" "^7.14.0" "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.13.14" - "@babel/helpers" "^7.13.16" - "@babel/parser" "^7.13.16" + "@babel/helper-module-transforms" "^7.14.0" + "@babel/helpers" "^7.14.0" + "@babel/parser" "^7.14.0" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -42,15 +42,6 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.13.16", "@babel/generator@^7.13.9": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.16.tgz#0befc287031a201d84cdfc173b46b320ae472d14" - integrity sha512-grBBR75UnKOcUWMp8WoDxNsWCFl//XCK6HWTrBQKTr5SV9f5g0pNOjdyzi/DTBv12S9GnYPInIXQBTky7OXEMg== - dependencies: - "@babel/types" "^7.13.16" - jsesc "^2.5.1" - source-map "^0.5.0" - "@babel/generator@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.0.tgz#0f35d663506c43e4f10898fbda0d752ec75494be" @@ -189,21 +180,7 @@ dependencies: "@babel/types" "^7.13.12" -"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14": - version "7.13.14" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef" - integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g== - dependencies: - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-simple-access" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.12.11" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.13" - "@babel/types" "^7.13.14" - -"@babel/helper-module-transforms@^7.14.0": +"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.0.tgz#8fcf78be220156f22633ee204ea81f73f826a8ad" integrity sha512-L40t9bxIuGOfpIGA3HNkJhU9qYrf4y5A5LUSw7rGMSn+pcG8dfJ0g6Zval6YJGd2nEjI7oP00fRdnhLKndx6bw== @@ -304,14 +281,14 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" -"@babel/helpers@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.16.tgz#08af075f786fd06a56e41bcac3e8cc87ddc4d0b3" - integrity sha512-x5otxUaLpdWHl02P4L94wBU+2BJXBkvO+6d6uzQ+xD9/h2hTSAwA5O8QV8GqKx/l8i+VYmKKQg9e2QGTa2Wu3Q== +"@babel/helpers@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" + integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== dependencies: "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": version "7.13.10" @@ -322,12 +299,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.13", "@babel/parser@^7.13.15", "@babel/parser@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" - integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== - -"@babel/parser@^7.14.0": +"@babel/parser@^7.12.13", "@babel/parser@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.0.tgz#2f0ebfed92bcddcc8395b91f1895191ce2760380" integrity sha512-AHbfoxesfBALg33idaTBVUkLnfXtsgvJREf93p4p0Lwsz4ppfE7g1tpEXVm4vrxUcH4DVhAa9Z1m1zqf9WUC7Q== @@ -1026,21 +998,7 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7" - integrity sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.15" - "@babel/types" "^7.13.14" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.14.0": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.0.tgz#cea0dc8ae7e2b1dec65f512f39f3483e8cc95aef" integrity sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA== @@ -1054,7 +1012,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.4.4": +"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.4.4": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.0.tgz#3fc3fc74e0cdad878182e5f66cc6bcab1915a802" integrity sha512-O2LVLdcnWplaGxiPBz12d0HcdN8QdxdsWYhz5LSeuukV/5mn2xUUc3gBeU4QBYPJ18g/UToe8F532XJ608prmg== From 5acb954b496b798147822aa2e2be887d4d3dad70 Mon Sep 17 00:00:00 2001 From: Pascal Holy <54705263+pascal-airy@users.noreply.github.com> Date: Mon, 3 May 2021 09:48:49 +0200 Subject: [PATCH 21/28] =?UTF-8?q?[#1687]=20Kafka=20Prometheus=20exporter?= =?UTF-8?q?=20error=20on=E2=80=A6=20(#1688)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1687 --- .../kafka/charts/kafka/templates/_helpers.tpl | 5 ++ .../kafka/templates/headless-service.yaml | 2 +- .../charts/kafka/templates/prometheus.yaml | 46 +++++++++++++++++++ .../kafka/charts/kafka/templates/service.yaml | 26 +++++++++-- .../charts/kafka/templates/statefulset.yaml | 13 +----- .../charts/kafka/charts/kafka/values.yaml | 9 ++-- 6 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl index 8e20b25515..fe026c0740 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl @@ -86,3 +86,8 @@ Create a variable containing all the datadirs created. {{- printf "/opt/kafka/data-%d/logs" $k -}} {{- end -}} {{- end -}} + +{{- define "kafka.prometheus.name" -}} +{{- $name := "prometheus-prometheus-kafka-exporter" -}} +{{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml index 79c04ff7db..c0ed8c0a8f 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml @@ -10,7 +10,7 @@ metadata: heritage: {{ .Release.Service }} spec: ports: - - port: 9092 + - port: {{ .Values.port }} name: broker clusterIP: None selector: diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml new file mode 100644 index 0000000000..28d5623ea1 --- /dev/null +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml @@ -0,0 +1,46 @@ +{{- if .Values.prometheus.enabled }} +{{- if .Capabilities.APIVersions.Has "apps/v1" }} +apiVersion: apps/v1 +{{- else }} +apiVersion: apps/v1beta2 +{{- end }} +kind: Deployment +metadata: + name: {{ template "kafka.prometheus.name" . }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ template "kafka.prometheus.name" . }} + chart: {{ template "kafka.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ template "kafka.prometheus.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "kafka.prometheus.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: prometheus + image: "{{ .Values.prometheus.exporterImage }}:{{ .Values.prometheus.exporterImageTag }}" + command: ["/bin/kafka_exporter"] + args: + - "--kafka.server={{ template "kafka.name" . }}:{{ .Values.port }}" + resources: + requests: + cpu: 100m + memory: 100Mi + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + ports: + - containerPort: {{ .Values.prometheus.exporterPort }} + name: prometheus + volumes: + - name: provisioning-scripts + configMap: + name: provisioning-scripts +{{ end }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml index fc15f7ad50..ebd6edba7e 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml @@ -8,13 +8,31 @@ metadata: chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} - core.airy.co/prometheus: kafka spec: ports: - - port: 9092 + - port: {{ .Values.port }} name: broker - - port: {{ .Values.prometheusExporterPort }} - name: prometheus selector: app: {{ template "kafka.name" . }} release: {{ .Release.Name }} +--- +{{- if .Values.prometheus.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kafka.prometheus.name" . }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ template "kafka.prometheus.name" . }} + chart: {{ template "kafka.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + core.airy.co/prometheus: {{ template "kafka.name" . }} +spec: + ports: + - port: {{ .Values.prometheus.exporterPort }} + name: prometheus + selector: + app: {{ template "kafka.prometheus.name" . }} + release: {{ .Release.Name }} +{{ end }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml index d2d70ff0ab..11ad7b06be 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml @@ -51,7 +51,7 @@ spec: image: "{{ .Values.image }}:{{ .Values.imageTag }}" imagePullPolicy: "{{ .Values.imagePullPolicy }}" ports: - - containerPort: 9092 + - containerPort: {{ .Values.port }} name: kafka {{- if .Values.nodeport.enabled }} {{- $brokers := .Values.brokers | int }} @@ -103,17 +103,6 @@ spec: mountPath: /opt/kafka/data-{{$k}} {{- end }} {{- end }} - - name: prometheus - image: "{{ .Values.prometheusExporterImage }}:{{ .Values.prometheusExporterImageTag }}" - resources: - requests: - cpu: 100m - memory: 100Mi - imagePullPolicy: "{{ .Values.imagePullPolicy }}" - ports: - - containerPort: {{ .Values.prometheusExporterPort }} - name: prometheus - {{- if .Values.imagePullSecrets }} imagePullSecrets: {{ toYaml .Values.imagePullSecrets | indent 8 }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml index cd91ac5b60..86ac2ef849 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml @@ -10,6 +10,7 @@ configurationOverrides: "log.retention.hours": "-1" "listener.security.protocol.map": |- PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT +port: 9092 firstListenerPort: 31090 persistence: enabled: true @@ -32,6 +33,8 @@ zookeeper: dataDirSize: 5Gi dataLogDirSize: 5Gi url: "" -prometheusExporterImage: danielqsj/kafka-exporter -prometheusExporterImageTag: v1.3.0 -prometheusExporterPort: 9308 \ No newline at end of file +prometheus: + enabled: false + exporterImage: danielqsj/kafka-exporter + exporterImageTag: v1.3.0 + exporterPort: 9308 From 6d0a759a68e366d3a3092b822831fa9b3f639fea Mon Sep 17 00:00:00 2001 From: Pascal Holy <54705263+pascal-airy@users.noreply.github.com> Date: Mon, 3 May 2021 10:57:05 +0200 Subject: [PATCH 22/28] [#1505] Rewrite Webhook queue with Beanstalkd (#1536) Resolves #1505 --- WORKSPACE | 3 +- .../webhook/{redis-worker => consumer}/BUILD | 18 +- backend/webhook/consumer/go.mod | 10 + backend/webhook/consumer/go.sum | 98 +++ backend/webhook/consumer/main.go | 58 ++ backend/webhook/consumer/pkg/worker/BUILD | 21 + .../webhook/consumer/pkg/worker/consumer.go | 97 +++ .../main.go => consumer/pkg/worker/server.go} | 23 +- backend/webhook/consumer/pkg/worker/worker.go | 158 +++++ backend/webhook/publisher/BUILD | 3 +- ...edisQueue.java => BeanstalkPublisher.java} | 23 +- .../core/webhook/publisher/Publisher.java | 14 +- .../config/BeanstalkProducerConfig.java | 22 + .../publisher/config/LettuceConfig.java | 16 - .../webhook/publisher/config/RedisConfig.java | 26 - .../publisher/payload/QueueMessage.java | 20 - .../src/main/resources/application.properties | 4 +- .../core/webhook/publisher/PublisherTest.java | 9 +- .../src/test/resources/test.properties | 4 +- backend/webhook/redis-worker/go.mod | 8 - backend/webhook/redis-worker/go.sum | 88 --- .../webhook/redis-worker/pkg/scheduler/BUILD | 25 - .../redis-worker/pkg/scheduler/consumer/BUILD | 15 - .../pkg/scheduler/consumer/consumer.go | 153 ----- .../redis-worker/pkg/scheduler/queue/BUILD | 12 - .../redis-worker/pkg/scheduler/queue/queue.go | 63 -- .../redis-worker/pkg/scheduler/scheduler.go | 80 --- .../pkg/scheduler/scheduler_test.go | 60 -- go.mod | 12 +- go.sum | 123 ++-- go_repositories.bzl | 269 ++++++--- .../api-admin/templates/deployment.yaml | 15 + .../charts/webhook/templates/deployments.yaml | 37 +- .../helm-chart/charts/beanstalkd/Chart.yaml | 5 + .../charts/beanstalkd/templates/service.yaml | 16 + .../beanstalkd/templates/statefulset.yaml | 39 ++ .../helm-chart/charts/beanstalkd/values.yaml | 8 + .../prerequisites/templates/beanstalk.yaml | 8 + .../charts/prerequisites/templates/redis.yaml | 8 - .../charts/prerequisites/values.yaml | 6 +- .../helm-chart/charts/redis/Chart.yaml | 5 - .../charts/redis/templates/configmap.yaml | 19 - .../charts/redis/templates/service.yaml | 16 - .../charts/redis/templates/statefulset.yaml | 50 -- .../helm-chart/charts/redis/values.yaml | 4 - infrastructure/tools/prometheus/values.yaml | 4 + maven_install.json | 559 ++++++------------ 47 files changed, 1110 insertions(+), 1224 deletions(-) rename backend/webhook/{redis-worker => consumer}/BUILD (68%) create mode 100644 backend/webhook/consumer/go.mod create mode 100644 backend/webhook/consumer/go.sum create mode 100644 backend/webhook/consumer/main.go create mode 100644 backend/webhook/consumer/pkg/worker/BUILD create mode 100644 backend/webhook/consumer/pkg/worker/consumer.go rename backend/webhook/{redis-worker/main.go => consumer/pkg/worker/server.go} (52%) create mode 100644 backend/webhook/consumer/pkg/worker/worker.go rename backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/{RedisQueue.java => BeanstalkPublisher.java} (52%) create mode 100644 backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java delete mode 100644 backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java delete mode 100644 backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java delete mode 100644 backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java delete mode 100644 backend/webhook/redis-worker/go.mod delete mode 100644 backend/webhook/redis-worker/go.sum delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/BUILD delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/queue/BUILD delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/queue/queue.go delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/scheduler.go delete mode 100644 backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go create mode 100644 infrastructure/helm-chart/charts/beanstalkd/Chart.yaml create mode 100644 infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml create mode 100644 infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml create mode 100644 infrastructure/helm-chart/charts/beanstalkd/values.yaml create mode 100644 infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml delete mode 100644 infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml delete mode 100644 infrastructure/helm-chart/charts/redis/Chart.yaml delete mode 100644 infrastructure/helm-chart/charts/redis/templates/configmap.yaml delete mode 100644 infrastructure/helm-chart/charts/redis/templates/service.yaml delete mode 100644 infrastructure/helm-chart/charts/redis/templates/statefulset.yaml delete mode 100644 infrastructure/helm-chart/charts/redis/values.yaml diff --git a/WORKSPACE b/WORKSPACE index 3fce84f6b3..40d940ed25 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -33,6 +33,7 @@ maven_install( "com.github.everit-org.json-schema:org.everit.json.schema:1.12.2", "com.google.auth:google-auth-library-oauth2-http:0.20.0", "com.jayway.jsonpath:json-path:2.4.0", + "com.dinstone:beanstalkc:2.3.0", "com.twilio.sdk:twilio:7.51.0", "io.confluent:kafka-avro-serializer:5.5.1", "io.confluent:kafka-schema-registry-client:5.5.1", @@ -41,7 +42,6 @@ maven_install( "io.jsonwebtoken:jjwt-api:0.10.5", "io.jsonwebtoken:jjwt-impl:0.10.5", "io.jsonwebtoken:jjwt-jackson:0.10.5", - "io.lettuce:lettuce-core:5.3.3.RELEASE", "io.micrometer:micrometer-registry-prometheus:1.6.5", "javax.activation:javax.activation-api:1.2.0", "javax.validation:validation-api:2.0.1.Final", @@ -83,7 +83,6 @@ maven_install( "org.springframework:spring-context:5.3.6", "org.springframework:spring-messaging:5.3.6", "org.springframework:spring-websocket:5.3.6", - "org.springframework.data:spring-data-redis:2.3.3.RELEASE", "org.springframework.security:spring-security-core:5.4.6", "org.rocksdb:rocksdbjni:5.18.3", ], diff --git a/backend/webhook/redis-worker/BUILD b/backend/webhook/consumer/BUILD similarity index 68% rename from backend/webhook/redis-worker/BUILD rename to backend/webhook/consumer/BUILD index 21bab2e1a9..dc7ef58c4a 100644 --- a/backend/webhook/redis-worker/BUILD +++ b/backend/webhook/consumer/BUILD @@ -1,4 +1,4 @@ -# gazelle:prefix redis-worker +# gazelle:prefix consumer load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") @@ -6,14 +6,14 @@ load("@io_bazel_rules_docker//go:image.bzl", "go_image") load("//tools/build:container_release.bzl", "container_release") go_binary( - name = "redis-worker_binary", - embed = [":redis-worker_lib"], + name = "consumer_binary", + embed = [":consumer_lib"], visibility = ["//visibility:public"], ) go_image( name = "image", - embed = [":redis-worker_lib"], + embed = [":consumer_lib"], ) container_release( @@ -21,12 +21,12 @@ container_release( repository = "consumer", ) +check_pkg(name = "buildifier") + go_library( - name = "redis-worker_lib", + name = "consumer_lib", srcs = ["main.go"], - importpath = "redis-worker", + importpath = "consumer", visibility = ["//visibility:private"], - deps = ["//backend/webhook/redis-worker/pkg/scheduler"], + deps = ["//backend/webhook/consumer/pkg/worker"], ) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/consumer/go.mod b/backend/webhook/consumer/go.mod new file mode 100644 index 0000000000..2fe45fe9ff --- /dev/null +++ b/backend/webhook/consumer/go.mod @@ -0,0 +1,10 @@ +module consumer + +go 1.16 + +require ( + github.com/Shopify/sarama v1.28.0 + github.com/beanstalkd/go-beanstalk v0.1.0 + github.com/jpillora/backoff v1.0.0 + github.com/riferrei/srclient v0.2.1 +) diff --git a/backend/webhook/consumer/go.sum b/backend/webhook/consumer/go.sum new file mode 100644 index 0000000000..c0b5db1153 --- /dev/null +++ b/backend/webhook/consumer/go.sum @@ -0,0 +1,98 @@ +github.com/Shopify/sarama v1.28.0 h1:lOi3SfE6OcFlW9Trgtked2aHNZ2BIG/d6Do+PEUAqqM= +github.com/Shopify/sarama v1.28.0/go.mod h1:j/2xTrU39dlzBmsxF1eQ2/DdWrxyBCl6pzz7a81o/ZY= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/beanstalkd/go-beanstalk v0.1.0 h1:IiNwYbAoVBDs5xEOmleGoX+DRD3Moz99EpATbl8672w= +github.com/beanstalkd/go-beanstalk v0.1.0/go.mod h1:/G8YTyChOtpOArwLTQPY1CHB+i212+av35bkPXXj56Y= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehOGrM= +github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= +github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= +github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/riferrei/srclient v0.2.1 h1:uIJhzPXW+suDsEDOZKf4oTZZXTyxtw98cFC70rFzvgU= +github.com/riferrei/srclient v0.2.1/go.mod h1:SmCz0lrYQ1pLqXlYq0yPnRccHLGh+llDA0i6hecPeW8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/webhook/consumer/main.go b/backend/webhook/consumer/main.go new file mode 100644 index 0000000000..d0c65203a5 --- /dev/null +++ b/backend/webhook/consumer/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "consumer/pkg/worker" + "context" + "log" + "os" + "os/signal" + "strconv" + "sync" + "syscall" + "time" +) + +func main() { + maxBackOffSeconds, err := strconv.Atoi(os.Getenv("MAX_BACKOFF_SECONDS")) + if err != nil { + log.Fatal("MAX_BACKOFF_SECONDS not set") + } + + ctx, cancel := context.WithCancel(context.Background()) + var wg sync.WaitGroup + + webhookConfigStream := make(chan string) + + kafkaConsumerConfig := worker.KafkaConsumerConfig{ + Brokers: os.Getenv("KAFKA_BROKERS"), + SchemaRegistryURL: os.Getenv("KAFKA_SCHEMA_REGISTRY_URL"), + Group: "WebhookConsumer", + Topics: "application.communication.webhooks", + } + + wg.Add(1) + go worker.StartKafkaConsumer(ctx, &wg, webhookConfigStream, kafkaConsumerConfig) + + w, err := worker.Start( + ctx, + &wg, + webhookConfigStream, + os.Getenv("BEANSTALK_HOSTNAME"), + os.Getenv("BEANSTALK_PORT"), + time.Duration(maxBackOffSeconds)*time.Second, + ) + if err != nil { + cancel() + } + + wg.Add(1) + go w.StartServer(ctx, &wg) + + sigterm := make(chan os.Signal, 1) + signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM) + + <-sigterm + log.Println("terminating: via signal") + cancel() + wg.Wait() +} diff --git a/backend/webhook/consumer/pkg/worker/BUILD b/backend/webhook/consumer/pkg/worker/BUILD new file mode 100644 index 0000000000..aa42f1db79 --- /dev/null +++ b/backend/webhook/consumer/pkg/worker/BUILD @@ -0,0 +1,21 @@ +load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +check_pkg(name = "buildifier") + +go_library( + name = "worker", + srcs = [ + "consumer.go", + "server.go", + "worker.go", + ], + importpath = "consumer/pkg/worker", + visibility = ["//visibility:public"], + deps = [ + "@com_github_beanstalkd_go_beanstalk//:go-beanstalk", + "@com_github_jpillora_backoff//:backoff", + "@com_github_riferrei_srclient//:srclient", + "@com_github_shopify_sarama//:sarama", + ], +) diff --git a/backend/webhook/consumer/pkg/worker/consumer.go b/backend/webhook/consumer/pkg/worker/consumer.go new file mode 100644 index 0000000000..bc4e4be13f --- /dev/null +++ b/backend/webhook/consumer/pkg/worker/consumer.go @@ -0,0 +1,97 @@ +package worker + +import ( + "context" + "encoding/binary" + "fmt" + "log" + "strings" + "sync" + + "github.com/Shopify/sarama" + "github.com/riferrei/srclient" +) + +type Consumer struct { + ready chan bool + webhookConfigStream chan string + schemaRegistryClient *srclient.SchemaRegistryClient +} + +type KafkaConsumerConfig struct { + Brokers, SchemaRegistryURL, Topics, Group string +} + +func StartKafkaConsumer( + ctx context.Context, + wg *sync.WaitGroup, + webhookConfigStream chan string, + kafkaConsumerConfig KafkaConsumerConfig, +) { + defer wg.Done() + config := sarama.NewConfig() + config.Consumer.Offsets.Initial = sarama.OffsetOldest + + schemaRegistryClient := srclient.CreateSchemaRegistryClient(kafkaConsumerConfig.SchemaRegistryURL) + + consumer := Consumer{ + ready: make(chan bool), + webhookConfigStream: webhookConfigStream, + schemaRegistryClient: schemaRegistryClient, + } + + client, err := sarama.NewConsumerGroup(strings.Split(kafkaConsumerConfig.Brokers, ","), kafkaConsumerConfig.Group, config) + if err != nil { + log.Panicf("Error creating consumer group client: %v", err) + } + + go func() { + for { + if err := client.Consume(ctx, strings.Split(kafkaConsumerConfig.Topics, ","), &consumer); err != nil { + log.Panicf("Error from consumer: %v", err) + } + if ctx.Err() != nil { + return + } + consumer.ready = make(chan bool) + } + }() + + <-consumer.ready + log.Println("Sarama consumer up and running!...") + + <-ctx.Done() + log.Println("terminating consumer: context cancelled") + if err = client.Close(); err != nil { + log.Panicf("Error closing client: %v", err) + } +} + +func (consumer *Consumer) Setup(sarama.ConsumerGroupSession) error { + close(consumer.ready) + return nil +} + +func (consumer *Consumer) Cleanup(sarama.ConsumerGroupSession) error { + return nil +} + +func (consumer *Consumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { + for config := range claim.Messages() { + consumer.publishWebhookConfig(config) + session.MarkMessage(config, "") + } + return nil +} + +func (consumer *Consumer) publishWebhookConfig(config *sarama.ConsumerMessage) { + schemaID := binary.BigEndian.Uint32(config.Value[1:5]) + schema, err := consumer.schemaRegistryClient.GetSchema(int(schemaID)) + if err != nil { + panic(fmt.Sprintf("Error getting the schema with id '%d' %s", schemaID, err)) + } + native, _, _ := schema.Codec().NativeFromBinary(config.Value[5:]) + value, _ := schema.Codec().TextualFromNative(nil, native) + + consumer.webhookConfigStream <- string(value) +} diff --git a/backend/webhook/redis-worker/main.go b/backend/webhook/consumer/pkg/worker/server.go similarity index 52% rename from backend/webhook/redis-worker/main.go rename to backend/webhook/consumer/pkg/worker/server.go index 6249504580..00197292b3 100644 --- a/backend/webhook/redis-worker/main.go +++ b/backend/webhook/consumer/pkg/worker/server.go @@ -1,18 +1,17 @@ -package main +package worker import ( + "context" "encoding/json" "log" "net/http" - "os" - "redis-worker/pkg/scheduler" + "sync" ) -func main() { - schedulerTask := scheduler.Start(os.Getenv("REDIS_HOSTNAME"), os.Getenv("REDIS_PORT")) - +func (worker *Worker) StartServer(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { - errors, err := json.Marshal(schedulerTask.GetStatuses()) + errors, err := json.Marshal(worker.GetErrors()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -29,5 +28,13 @@ func main() { w.WriteHeader(200) }) - log.Fatal(http.ListenAndServe(":8080", nil)) + go func() { + log.Println("serving on 8080") + err := http.ListenAndServe(":8080", nil) + if err != nil { + panic("ListenAndServe: " + err.Error()) + } + }() + <-ctx.Done() + log.Println("terminating server: context cancelled") } diff --git a/backend/webhook/consumer/pkg/worker/worker.go b/backend/webhook/consumer/pkg/worker/worker.go new file mode 100644 index 0000000000..2cea9585db --- /dev/null +++ b/backend/webhook/consumer/pkg/worker/worker.go @@ -0,0 +1,158 @@ +package worker + +import ( + "context" + "encoding/json" + "errors" + "sync" + + "github.com/beanstalkd/go-beanstalk" + "github.com/jpillora/backoff" + + "bytes" + "fmt" + + "log" + "net/http" + "time" +) + +type Worker struct { + endpoint string + customHeader map[string]string + beanstalk *beanstalk.Conn + backoff *backoff.Backoff + errors []consumerError +} +type consumerError struct { + Err error + T time.Time +} + +type webhookConfig struct { + Id string + Endpoint string + Headers map[string]map[string]string + Status string +} + +func Start( + ctx context.Context, + wg *sync.WaitGroup, + webhookConfigStream chan string, + hostname, port string, + maxBackoff time.Duration, +) (*Worker, error) { + + conn, err := beanstalk.Dial("tcp", fmt.Sprintf("%s:%s", hostname, port)) + + if err != nil { + return nil, err + } + + w := Worker{ + endpoint: "", + customHeader: make(map[string]string), + beanstalk: conn, + backoff: &backoff.Backoff{Max: maxBackoff}, + errors: make([]consumerError, 0), + } + + wg.Add(2) + go w.Run(ctx, wg) + go w.updateWebhookConfig(ctx, wg, webhookConfigStream) + return &w, nil +} + +func (w *Worker) Run(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + for { + select { + case <-ctx.Done(): + log.Println("terminating worker: context canceled ") + return + default: + id, event, err := w.beanstalk.Reserve(1 * time.Minute) + if err != nil { + if !errors.Is(err, beanstalk.ErrTimeout) { + log.Println(err) + } + continue + } + + for { + select { + case <-ctx.Done(): + log.Println("terminating worker: context cancelled") + return + default: + err = w.HandleEvent(event) + if err != nil { + w.logError(err) + time.Sleep(w.backoff.Duration()) + continue + } + err = w.beanstalk.Delete(id) + if err != nil { + w.logError(err) + } + w.backoff.Reset() + break + } + } + } + } +} + +func (w *Worker) updateWebhookConfig(ctx context.Context, wg *sync.WaitGroup, webhookConfigStream chan string) { + defer wg.Done() + log.Println("Started updateWebhookConfig routine") + select { + case <-ctx.Done(): + log.Println("terminating updateWebhookConfig: context cancelled") + case config := <-webhookConfigStream: + var webhookConfig = webhookConfig{} + if err := json.Unmarshal([]byte(config), &webhookConfig); err != nil { + log.Fatal(err) + } + w.endpoint = webhookConfig.Endpoint + w.customHeader = webhookConfig.Headers["map"] + } +} + +func (w *Worker) HandleEvent(data []byte) error { + req, _ := http.NewRequest("POST", w.endpoint, bytes.NewBuffer(data)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("User-Agent", "Airy/1.0") + + for k, v := range w.customHeader { + req.Header.Set(k, v) + } + + client := &http.Client{ + Timeout: 10 * time.Second, + } + endpointResp, err := client.Do(req) + + if err != nil { + return err + } + + if endpointResp.StatusCode > 299 { + return fmt.Errorf("%v returned status code %v", w.endpoint, endpointResp.StatusCode) + } + + return nil +} + +func (t *Worker) logError(err error) { + log.Println(err) + t.errors = append(t.errors, consumerError{ + Err: err, + T: time.Now(), + }) +} + +func (t *Worker) GetErrors() []consumerError { + return t.errors +} diff --git a/backend/webhook/publisher/BUILD b/backend/webhook/publisher/BUILD index 4141c9c2cf..991ac516b5 100644 --- a/backend/webhook/publisher/BUILD +++ b/backend/webhook/publisher/BUILD @@ -13,8 +13,7 @@ app_deps = [ "//lib/java/date", "//lib/java/spring/kafka/core:spring-kafka-core", "//lib/java/spring/kafka/streams:spring-kafka-streams", - "@maven//:io_lettuce_lettuce_core", - "@maven//:org_springframework_data_spring_data_redis", + "@maven//:com_dinstone_beanstalkc", ] springboot( diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/RedisQueue.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/BeanstalkPublisher.java similarity index 52% rename from backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/RedisQueue.java rename to backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/BeanstalkPublisher.java index d248a664c5..3c19d635e1 100644 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/RedisQueue.java +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/BeanstalkPublisher.java @@ -1,34 +1,35 @@ package co.airy.core.webhook.publisher; -import co.airy.core.webhook.publisher.payload.QueueMessage; import co.airy.log.AiryLoggerFactory; +import co.airy.model.event.payload.Event; +import com.dinstone.beanstalkc.JobProducer; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import org.slf4j.Logger; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service -public class RedisQueue { - private static final Logger log = AiryLoggerFactory.getLogger(RedisQueue.class); +public class BeanstalkPublisher { + private static final Logger log = AiryLoggerFactory.getLogger(BeanstalkPublisher.class); - final ObjectMapper objectMapper = new ObjectMapper() + private ObjectMapper objectMapper = new ObjectMapper() .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) .setSerializationInclusion(JsonInclude.Include.NON_NULL); - private final RedisTemplate redisTemplate; + private final JobProducer beanstalkdJobProducer; - RedisQueue(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; + BeanstalkPublisher(JobProducer beanstalkdJobProducer) { + this.beanstalkdJobProducer = beanstalkdJobProducer; } - void publishMessage(String webhookId, QueueMessage message) { + + void publishMessage(Event event) { try { - redisTemplate.opsForList().leftPush(webhookId, objectMapper.writeValueAsString(message)); + beanstalkdJobProducer.putJob(1, 1, 5000, objectMapper.writeValueAsBytes(event)); } catch (JsonProcessingException e) { - log.error("failed to publish message to redis", e); + log.error("Failed to publish event to Beanstalkd", e); } } } diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java index ea55085a5d..b7abba7e77 100644 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java @@ -4,7 +4,6 @@ import co.airy.avro.communication.Metadata; import co.airy.avro.communication.Status; import co.airy.avro.communication.Webhook; -import co.airy.core.webhook.publisher.payload.QueueMessage; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; import co.airy.kafka.schema.application.ApplicationCommunicationWebhooks; @@ -37,11 +36,11 @@ public class Publisher implements ApplicationListener, private final String webhooksStore = "webhook-store"; private final String allWebhooksKey = "339ab777-92aa-43a5-b452-82e73c50fc59"; private final KafkaStreamsWrapper streams; - private final RedisQueue redisQueuePublisher; + private final BeanstalkPublisher beanstalkdPublisher; - public Publisher(KafkaStreamsWrapper streams, RedisQueue redisQueuePublisher) { + public Publisher(KafkaStreamsWrapper streams, BeanstalkPublisher beanstalkdPublisher) { this.streams = streams; - this.redisQueuePublisher = redisQueuePublisher; + this.beanstalkdPublisher = beanstalkdPublisher; } private void startStream() { @@ -70,12 +69,7 @@ private void publishRecord(Serializable record) { final Webhook webhook = webhookStore.get(allWebhooksKey); if (webhook != null && webhook.getStatus().equals(Status.Subscribed)) { - redisQueuePublisher.publishMessage(webhook.getId(), QueueMessage.builder() - .body(fromRecord(record)) - .endpoint(webhook.getEndpoint()) - .headers(webhook.getHeaders()) - .build() - ); + beanstalkdPublisher.publishMessage(fromRecord(record)); } } catch (Exception e) { log.error("failed to publish record", e); diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java new file mode 100644 index 0000000000..da3af61d69 --- /dev/null +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java @@ -0,0 +1,22 @@ +package co.airy.core.webhook.publisher.config; + +import com.dinstone.beanstalkc.BeanstalkClientFactory; +import com.dinstone.beanstalkc.JobProducer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class BeanstalkProducerConfig { + + @Bean + public JobProducer beanstalkJobProducer(@Value("${beanstalk.hostname}") String hostName, @Value("${beanstalk.port}") int port) { + com.dinstone.beanstalkc.Configuration config = new com.dinstone.beanstalkc.Configuration(); + config.setServiceHost(hostName); + config.setServicePort(port); + config.setConnectTimeout(2000); + config.setReadTimeout(3000); + BeanstalkClientFactory beanstalkClientFactory = new BeanstalkClientFactory(config); + return beanstalkClientFactory.createJobProducer("default"); + } +} diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java deleted file mode 100644 index e64637802f..0000000000 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package co.airy.core.webhook.publisher.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; - -@Configuration -public class LettuceConfig { - - @Bean - public LettuceConnectionFactory redisConnectionFactory(@Value("${redis.url}") final String hostName, @Value("${redis.port}") final int port) { - return new LettuceConnectionFactory(new RedisStandaloneConfiguration(hostName, port)); - } -} diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java deleted file mode 100644 index fe1a1014cc..0000000000 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package co.airy.core.webhook.publisher.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - private final LettuceConnectionFactory redisConnectionFactory; - - RedisConfig(LettuceConnectionFactory redisConnectionFactory) { - this.redisConnectionFactory = redisConnectionFactory; - } - - @Bean - public RedisTemplate redisTemplate() { - RedisTemplate stringTemplate = new RedisTemplate<>(); - stringTemplate.setConnectionFactory(redisConnectionFactory); - stringTemplate.setDefaultSerializer(new StringRedisSerializer()); - stringTemplate.afterPropertiesSet(); - - return stringTemplate; - } -} diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java deleted file mode 100644 index 613495fb3d..0000000000 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java +++ /dev/null @@ -1,20 +0,0 @@ -package co.airy.core.webhook.publisher.payload; - -import co.airy.model.event.payload.Event; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.io.Serializable; -import java.util.Map; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class QueueMessage implements Serializable { - private String endpoint; - private Map headers; - private Event body; -} diff --git a/backend/webhook/publisher/src/main/resources/application.properties b/backend/webhook/publisher/src/main/resources/application.properties index dc8be7692e..efac0b55d3 100644 --- a/backend/webhook/publisher/src/main/resources/application.properties +++ b/backend/webhook/publisher/src/main/resources/application.properties @@ -3,5 +3,5 @@ kafka.schema-registry-url=${KAFKA_SCHEMA_REGISTRY_URL} kafka.cleanup=${KAFKA_CLEANUP:false} kafka.commit-interval-ms=${KAFKA_COMMIT_INTERVAL_MS} -redis.url=${REDIS_HOSTNAME} -redis.port=${REDIS_PORT} +beanstalk.hostname=${BEANSTALK_HOSTNAME} +beanstalk.port=${BEANSTALK_PORT} diff --git a/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java b/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java index b0fa3ef8bd..4119ddbb68 100644 --- a/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java +++ b/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java @@ -4,12 +4,12 @@ import co.airy.avro.communication.Message; import co.airy.avro.communication.Status; import co.airy.avro.communication.Webhook; -import co.airy.core.webhook.publisher.payload.QueueMessage; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; import co.airy.kafka.schema.application.ApplicationCommunicationWebhooks; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; +import co.airy.model.event.payload.Event; import co.airy.spring.core.AirySpringBootApplication; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; @@ -20,7 +20,6 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -72,7 +71,7 @@ static void afterAll() throws Exception { Publisher publisher; @MockBean - private RedisQueue redisQueue; + private BeanstalkPublisher beanstalkPublisher; @BeforeEach void beforeEach() throws InterruptedException { @@ -94,8 +93,8 @@ void canPublishMessageToQueue() throws Exception { TimeUnit.SECONDS.sleep(2); - ArgumentCaptor batchCaptor = ArgumentCaptor.forClass(QueueMessage.class); - doNothing().when(redisQueue).publishMessage(Mockito.anyString(), batchCaptor.capture()); + ArgumentCaptor batchCaptor = ArgumentCaptor.forClass(Event.class); + doNothing().when(beanstalkPublisher).publishMessage(batchCaptor.capture()); List> messages = new ArrayList<>(); diff --git a/backend/webhook/publisher/src/test/resources/test.properties b/backend/webhook/publisher/src/test/resources/test.properties index 160ec0212b..0cb65c22c5 100644 --- a/backend/webhook/publisher/src/test/resources/test.properties +++ b/backend/webhook/publisher/src/test/resources/test.properties @@ -1,5 +1,5 @@ kafka.cleanup=true kafka.cache.max.bytes=0 kafka.commit-interval-ms=100 -redis.url=no -redis.port=10 \ No newline at end of file +beanstalk.hostname=no +beanstalk.port=10 diff --git a/backend/webhook/redis-worker/go.mod b/backend/webhook/redis-worker/go.mod deleted file mode 100644 index eb01405e93..0000000000 --- a/backend/webhook/redis-worker/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module redis-worker - -go 1.16 - -require ( - github.com/alicebob/miniredis/v2 v2.13.3 - github.com/go-redis/redis/v8 v8.2.2 -) diff --git a/backend/webhook/redis-worker/go.sum b/backend/webhook/redis-worker/go.sum deleted file mode 100644 index 7e5bc4c44b..0000000000 --- a/backend/webhook/redis-worker/go.sum +++ /dev/null @@ -1,88 +0,0 @@ -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.13.3 h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw= -github.com/alicebob/miniredis/v2 v2.13.3/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-redis/redis/v8 v8.2.2 h1:A1tQgdeVF23Ojc1TIRpVuVfOadUdIM0vFVURigoPEMM= -github.com/go-redis/redis/v8 v8.2.2/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= -go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= -go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/webhook/redis-worker/pkg/scheduler/BUILD b/backend/webhook/redis-worker/pkg/scheduler/BUILD deleted file mode 100644 index 6386a30d1a..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/BUILD +++ /dev/null @@ -1,25 +0,0 @@ -load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "scheduler", - srcs = ["scheduler.go"], - importpath = "redis-worker/pkg/scheduler", - visibility = ["//visibility:public"], - deps = [ - "//backend/webhook/redis-worker/pkg/scheduler/consumer", - "//backend/webhook/redis-worker/pkg/scheduler/queue", - ], -) - -go_test( - name = "scheduler_test", - srcs = ["scheduler_test.go"], - embed = [":scheduler"], - deps = [ - "//backend/webhook/redis-worker/pkg/scheduler/queue", - "@com_github_alicebob_miniredis_v2//:miniredis", - ], -) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD b/backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD deleted file mode 100644 index 0674e1702b..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD +++ /dev/null @@ -1,15 +0,0 @@ -load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "consumer", - srcs = ["consumer.go"], - importpath = "redis-worker/pkg/scheduler/consumer", - visibility = ["//visibility:public"], - deps = [ - "//backend/webhook/redis-worker/pkg/scheduler/queue", - "@com_github_go_redis_redis_v8//:redis", - ], -) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go b/backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go deleted file mode 100644 index 4c7a0b09ae..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go +++ /dev/null @@ -1,153 +0,0 @@ -package consumer - -import ( - "bytes" - "encoding/json" - "fmt" - "redis-worker/pkg/scheduler/queue" - - "log" - "net/http" - "time" - - "github.com/go-redis/redis/v8" -) - -type ConsumerError struct { - Err error - T time.Time -} - -type Task struct { - done chan bool - queue string - waitInS int32 - rdb *redis.Client - errors []ConsumerError -} - -type AiryMessage struct { - Endpoint string - Headers map[string]string - Body map[string]interface{} -} - -func StartConsumer(rdb *redis.Client, queue string) Task { - t := &Task{ - queue: queue, - waitInS: 2, - rdb: rdb, - done: make(chan bool), - errors: make([]ConsumerError, 0), - } - - go func() { - for { - t.Run() - } - }() - - log.Printf("consumer spawned [%s]", queue) - return *t -} - -func (t *Task) GetErrors() []ConsumerError { - return t.errors -} - -const endpointRequestTimeout = 60 - -func (t *Task) HandleMessage(message string) error { - data := &AiryMessage{} - - if err := json.Unmarshal([]byte(message), &data); err != nil { - return err - } - - jsonString, err := json.Marshal(data.Body) - - if err != nil { - return err - } - - req, _ := http.NewRequest("POST", data.Endpoint, bytes.NewBuffer(jsonString)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("User-Agent", "Airy/1.0") - - for k, v := range data.Headers { - req.Header.Set(k, v) - } - - client := &http.Client{ - Timeout: endpointRequestTimeout * time.Second, - } - endpointResp, err := client.Do(req) - - if err != nil { - return err - } - - if endpointResp.StatusCode > 299 { - return fmt.Errorf("%v returned status code %v", data.Endpoint, endpointResp.StatusCode) - } - - return nil -} - -func (t *Task) logError(err error) { - log.Println(err) - t.errors = append(t.errors, ConsumerError{ - Err: err, - T: time.Now(), - }) -} - -func (t *Task) Run() { - retry := 0 - maxRetries := 10 - processingQueue := t.queue + "_processing" - - q := queue.NewQueue(t.rdb) - - result, err := q.Dequeue(processingQueue) - if err != nil { - t.logError(fmt.Errorf("Failed to dequeue \n%w", err)) - return - } - - if len(result) > 0 { - message := result[0] - if err = t.HandleMessage(message); err != nil { - t.logError(fmt.Errorf("error when processing message for queue %v\n%w", processingQueue, err)) - time.Sleep(time.Duration(t.waitInS) * time.Second) - t.waitInS = 2 * t.waitInS - return - - } - t.waitInS = 2 - q.DeleteFromQueue(processingQueue, message) - } - fmt.Println("nothing in processing") - - message, err := q.DequeueEnqueue(t.queue, processingQueue) - - if err != nil { - t.logError(fmt.Errorf("failed to receive messages %s", err)) - return - } - - for retry < maxRetries { - if err = t.HandleMessage(message); err != nil { - t.logError(fmt.Errorf("error when processing message for queue %v\n%w", t.queue, err)) - time.Sleep(time.Duration(t.waitInS) * time.Second) - t.waitInS = 2 * t.waitInS - retry = retry + 1 - fmt.Println("retry %i", retry) - - } else { - q.DeleteFromQueue(processingQueue, message) - t.waitInS = 2 - break - } - } -} diff --git a/backend/webhook/redis-worker/pkg/scheduler/queue/BUILD b/backend/webhook/redis-worker/pkg/scheduler/queue/BUILD deleted file mode 100644 index 0b4154f244..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/queue/BUILD +++ /dev/null @@ -1,12 +0,0 @@ -load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "queue", - srcs = ["queue.go"], - importpath = "redis-worker/pkg/scheduler/queue", - visibility = ["//visibility:public"], - deps = ["@com_github_go_redis_redis_v8//:redis"], -) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/redis-worker/pkg/scheduler/queue/queue.go b/backend/webhook/redis-worker/pkg/scheduler/queue/queue.go deleted file mode 100644 index 1185e6c4f6..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/queue/queue.go +++ /dev/null @@ -1,63 +0,0 @@ -package queue - -import ( - "context" - "fmt" - "time" - - "github.com/go-redis/redis/v8" -) - -type Queue struct { - ctx context.Context - Rdb *redis.Client -} - -func NewQueue(Rdb *redis.Client) Queue { - q := &Queue{ - ctx: context.Background(), - Rdb: Rdb, - } - return *q -} - -func GetClient(hostname, port string) *redis.Client { - return redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%s", hostname, port), - Password: "", // no password set - DB: 0, // use default DB - }) -} - -func (q *Queue) GetAllQueues() ([]string, error) { - var cursor uint64 - var keys []string - for { - var err error - keys, cursor, err = q.Rdb.Scan(q.ctx, cursor, "*", 10).Result() - if err != nil { - return nil, err - } - if cursor == 0 { - break - } - } - - return keys, nil -} - -func (q *Queue) DequeueEnqueue(queue, processingQueue string) (string, error) { - return q.Rdb.BRPopLPush(q.ctx, queue, processingQueue, 130*time.Second).Result() -} - -func (q *Queue) Dequeue(queue string) ([]string, error) { - return q.Rdb.LRange(q.ctx, queue, 0, 0).Result() -} - -func (q *Queue) DeleteFromQueue(queue, message string) { - q.Rdb.LRem(q.ctx, queue, 1, message) -} - -func (q *Queue) Enqueue(queue, message string) *redis.IntCmd { - return q.Rdb.RPush(q.ctx, queue, message) -} diff --git a/backend/webhook/redis-worker/pkg/scheduler/scheduler.go b/backend/webhook/redis-worker/pkg/scheduler/scheduler.go deleted file mode 100644 index d0e36254fd..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/scheduler.go +++ /dev/null @@ -1,80 +0,0 @@ -package scheduler - -import ( - "fmt" - "redis-worker/pkg/scheduler/queue" - "regexp" - - "log" - "redis-worker/pkg/scheduler/consumer" - "time" -) - -type Task struct { - ticker *time.Ticker - queue queue.Queue - consumers map[string]consumer.Task -} - -func Start(hostname, port string) *Task { - t := &Task{ - ticker: time.NewTicker(time.Minute), - queue: queue.NewQueue(queue.GetClient(hostname, port)), - consumers: make(map[string]consumer.Task), - } - - go func() { - t.updateConsumers(t.queue) - for range t.ticker.C { - t.updateConsumers(t.queue) - } - }() - - log.Println("queue consumer scheduler started") - return t -} - -type ConsumerStatus struct { - Errors []consumer.ConsumerError - Queue string -} - -func (t *Task) GetStatuses() []ConsumerStatus { - errors := make([]ConsumerStatus, len(t.consumers)) - - for k, v := range t.consumers { - if err := v.GetErrors(); err != nil { - errors = append(errors, ConsumerStatus{ - Errors: err, - Queue: k, - }) - } - } - - return errors -} - -func (t *Task) updateConsumers(q queue.Queue) { - queues, err := q.GetAllQueues() - - if err != nil { - log.Println("failed to fetch queues", err) - } - - for _, it := range queues { - fmt.Println(it) - if _, ok := t.consumers[it]; !ok && !isProcessingQueue(it) { - t.consumers[it] = consumer.StartConsumer(t.queue.Rdb, it) - } - } -} - -func isProcessingQueue(queue string) bool { - matched, err := regexp.MatchString(`.*_processing`, queue) - - if err != nil { - panic(err) - } - - return matched -} diff --git a/backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go b/backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go deleted file mode 100644 index 7b25b49cf2..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package scheduler - -import ( - "redis-worker/pkg/scheduler/queue" - "strings" - - "github.com/alicebob/miniredis/v2" - - "testing" -) - -func mockRedis() *miniredis.Miniredis { - s, err := miniredis.Run() - - if err != nil { - panic(err) - } - - return s -} - -func TestScheduler(t *testing.T) { - redisServer := setup() - defer teardown(redisServer) - - addr := strings.Split(redisServer.Addr(), ":") - schedulerTask := Start(addr[0], addr[1]) - - queues, _ := schedulerTask.queue.GetAllQueues() - q := queue.NewQueue(schedulerTask.queue.Rdb) - - if len(queues) != 0 { - t.Error("expected empty queue") - } - - testMessage := "{\"endpoint\":\"https://airy-platform-status.herokuapp.com/receive-message\",\"headers\":{\"X-Custom-Header\":\"custom-code-for-header\"},\"body\":{\"conversation_id\":\"2477cf76-633f-4343-bb22-49983b735131\",\"id\":\"bc685c4e-211f-4ef5-adf7-636ffe78279d\",\"text\":\"All work and no play makes Jack a dull boy\",\"sender\":{\"id\":\"433e835e-76d3-4351-82e7-1c8363766639\"},\"sent_at\":\"2020-09-21T18:50:23.155Z\",\"source\":\"FACEBOOK\",\"postback\":{}}}" - - q.Enqueue("test_queue", testMessage) - q.Enqueue("test_queue_processing", testMessage) - - schedulerTask.updateConsumers(q) - - queues, _ = q.GetAllQueues() - - if len(queues) != 2 { - t.Error("expected there to be two queues") - } - - if len(schedulerTask.consumers) != 1 { - t.Error("expected scheduler to spawn one consumer task") - } -} - -func setup() *miniredis.Miniredis { - return mockRedis() -} - -func teardown(redisServer *miniredis.Miniredis) { - redisServer.Close() -} diff --git a/go.mod b/go.mod index a546c3b251..f2be033ef2 100644 --- a/go.mod +++ b/go.mod @@ -6,30 +6,32 @@ go 1.16 // Automatically generated by running //tools/update-deps require ( - github.com/alicebob/miniredis/v2 v2.13.3 - github.com/go-redis/redis/v8 v8.2.2 + github.com/Shopify/sarama v1.28.0 github.com/TwinProduction/go-color v1.0.0 github.com/aws/aws-sdk-go v1.37.29 github.com/aws/aws-sdk-go-v2/config v1.1.1 github.com/aws/aws-sdk-go-v2/service/ec2 v1.1.1 github.com/aws/aws-sdk-go-v2/service/eks v1.1.1 github.com/aws/aws-sdk-go-v2/service/iam v1.1.1 + github.com/beanstalkd/go-beanstalk v0.1.0 github.com/imdario/mergo v0.3.11 // indirect + github.com/jpillora/backoff v1.0.0 github.com/kr/pretty v0.2.1 github.com/mitchellh/go-homedir v1.1.0 + github.com/riferrei/srclient v0.2.1 github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.1 github.com/spf13/viper v1.7.1 + github.com/stretchr/testify v1.7.0 github.com/thanhpk/randstr v1.0.4 github.com/txn2/txeh v1.3.0 goji.io v2.0.2+incompatible + golang.org/x/mod v0.4.1 + golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.19.0 k8s.io/apimachinery v0.19.0 k8s.io/client-go v0.19.0 k8s.io/klog v1.0.0 - golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect - github.com/stretchr/testify v1.6.1 - golang.org/x/mod v0.4.1 ) diff --git a/go.sum b/go.sum index 1747e4d00a..737bbe1c2b 100644 --- a/go.sum +++ b/go.sum @@ -48,16 +48,16 @@ github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzV github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.28.0 h1:lOi3SfE6OcFlW9Trgtked2aHNZ2BIG/d6Do+PEUAqqM= +github.com/Shopify/sarama v1.28.0/go.mod h1:j/2xTrU39dlzBmsxF1eQ2/DdWrxyBCl6pzz7a81o/ZY= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/TwinProduction/go-color v1.0.0 h1:8n59tqmLmt8jyRsY44RPy2ixPDDw0FcVoAhlYeyz3Jw= github.com/TwinProduction/go-color v1.0.0/go.mod h1:5hWpSyT+mmKPjCwPNEruBW5Dkbs/2PwOuU468ntEXNQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.13.3 h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw= -github.com/alicebob/miniredis/v2 v2.13.3/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= @@ -90,6 +90,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 h1:TJoIfnIFubCX0ACVeJ0w46HEH5Mwj github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/beanstalkd/go-beanstalk v0.1.0 h1:IiNwYbAoVBDs5xEOmleGoX+DRD3Moz99EpATbl8672w= +github.com/beanstalkd/go-beanstalk v0.1.0/go.mod h1:/G8YTyChOtpOArwLTQPY1CHB+i212+av35bkPXXj56Y= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -101,8 +103,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= @@ -129,19 +129,25 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= @@ -154,6 +160,10 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -180,8 +190,6 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5 github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-redis/redis/v8 v8.2.2 h1:A1tQgdeVF23Ojc1TIRpVuVfOadUdIM0vFVURigoPEMM= -github.com/go-redis/redis/v8 v8.2.2/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -210,6 +218,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -218,7 +229,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -241,6 +251,10 @@ github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyyc github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= @@ -272,8 +286,9 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -298,12 +313,26 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -319,6 +348,8 @@ github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= @@ -329,8 +360,11 @@ github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehOGrM= +github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -370,28 +404,23 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= +github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -415,6 +444,10 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzr github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/riferrei/srclient v0.2.1 h1:uIJhzPXW+suDsEDOZKf4oTZZXTyxtw98cFC70rFzvgU= +github.com/riferrei/srclient v0.2.1/go.mod h1:SmCz0lrYQ1pLqXlYq0yPnRccHLGh+llDA0i6hecPeW8= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af h1:gu+uRPtBe88sKxUCEXRoeCvVG90TJmwhiqRpvdhQFng= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -464,8 +497,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo= @@ -476,20 +510,20 @@ github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E= github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= -go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= @@ -506,8 +540,10 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -551,11 +587,12 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -566,8 +603,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -576,7 +614,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -584,21 +621,24 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -630,8 +670,9 @@ golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -678,8 +719,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -700,8 +742,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go_repositories.bzl b/go_repositories.bzl index d779aa6f38..e7bf2ec90d 100644 --- a/go_repositories.bzl +++ b/go_repositories.bzl @@ -21,19 +21,6 @@ def go_repositories(): version = "v0.0.0-20151022065526-2efee857e7cf", ) - go_repository( - name = "com_github_alicebob_gopher_json", - importpath = "github.com/alicebob/gopher-json", - sum = "h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=", - version = "v0.0.0-20200520072559-a9ecdc9d1d3a", - ) - go_repository( - name = "com_github_alicebob_miniredis_v2", - importpath = "github.com/alicebob/miniredis/v2", - sum = "h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw=", - version = "v2.13.3", - ) - go_repository( name = "com_github_armon_circbuf", importpath = "github.com/armon/circbuf", @@ -170,6 +157,13 @@ def go_repositories(): sum = "h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=", version = "v0.5.0", ) + go_repository( + name = "com_github_beanstalkd_go_beanstalk", + importpath = "github.com/beanstalkd/go-beanstalk", + sum = "h1:IiNwYbAoVBDs5xEOmleGoX+DRD3Moz99EpATbl8672w=", + version = "v0.1.0", + ) + go_repository( name = "com_github_beorn7_perks", importpath = "github.com/beorn7/perks", @@ -215,12 +209,6 @@ def go_repositories(): version = "v1.1.0", ) - go_repository( - name = "com_github_cespare_xxhash_v2", - importpath = "github.com/cespare/xxhash/v2", - sum = "h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=", - version = "v2.1.1", - ) go_repository( name = "com_github_chzyer_logex", importpath = "github.com/chzyer/logex", @@ -297,6 +285,12 @@ def go_repositories(): sum = "h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=", version = "v2.0.0", ) + go_repository( + name = "com_github_creack_pty", + importpath = "github.com/creack/pty", + sum = "h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=", + version = "v1.1.9", + ) go_repository( name = "com_github_davecgh_go_spew", @@ -311,12 +305,6 @@ def go_repositories(): version = "v3.2.0+incompatible", ) - go_repository( - name = "com_github_dgryski_go_rendezvous", - importpath = "github.com/dgryski/go-rendezvous", - sum = "h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=", - version = "v0.0.0-20200823014737-9f7001d12a5f", - ) go_repository( name = "com_github_dgryski_go_sip13", importpath = "github.com/dgryski/go-sip13", @@ -336,6 +324,24 @@ def go_repositories(): sum = "h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=", version = "v0.0.0-20180111231733-ee0de3bc6815", ) + go_repository( + name = "com_github_eapache_go_resiliency", + importpath = "github.com/eapache/go-resiliency", + sum = "h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=", + version = "v1.2.0", + ) + go_repository( + name = "com_github_eapache_go_xerial_snappy", + importpath = "github.com/eapache/go-xerial-snappy", + sum = "h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=", + version = "v0.0.0-20180814174437-776d5712da21", + ) + go_repository( + name = "com_github_eapache_queue", + importpath = "github.com/eapache/queue", + sum = "h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=", + version = "v1.1.0", + ) go_repository( name = "com_github_elazarl_goproxy", @@ -373,6 +379,18 @@ def go_repositories(): sum = "h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=", version = "v1.7.0", ) + go_repository( + name = "com_github_fortytw2_leaktest", + importpath = "github.com/fortytw2/leaktest", + sum = "h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=", + version = "v1.3.0", + ) + go_repository( + name = "com_github_frankban_quicktest", + importpath = "github.com/frankban/quicktest", + sum = "h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=", + version = "v1.11.3", + ) go_repository( name = "com_github_fsnotify_fsnotify", @@ -442,13 +460,6 @@ def go_repositories(): version = "v0.0.0-20160704191624-1d0bd113de87", ) - go_repository( - name = "com_github_go_redis_redis_v8", - importpath = "github.com/go-redis/redis/v8", - sum = "h1:A1tQgdeVF23Ojc1TIRpVuVfOadUdIM0vFVURigoPEMM=", - version = "v8.2.2", - ) - go_repository( name = "com_github_go_stack_stack", importpath = "github.com/go-stack/stack", @@ -488,6 +499,12 @@ def go_repositories(): sum = "h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=", version = "v1.4.2", ) + go_repository( + name = "com_github_golang_snappy", + importpath = "github.com/golang/snappy", + sum = "h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=", + version = "v0.0.2", + ) go_repository( name = "com_github_google_btree", @@ -552,6 +569,18 @@ def go_repositories(): sum = "h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=", version = "v0.0.0-20181017120253-0766667cb4d1", ) + go_repository( + name = "com_github_gorilla_securecookie", + importpath = "github.com/gorilla/securecookie", + sum = "h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=", + version = "v1.1.1", + ) + go_repository( + name = "com_github_gorilla_sessions", + importpath = "github.com/gorilla/sessions", + sum = "h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=", + version = "v1.2.1", + ) go_repository( name = "com_github_gorilla_websocket", @@ -652,8 +681,8 @@ def go_repositories(): go_repository( name = "com_github_hashicorp_go_uuid", importpath = "github.com/hashicorp/go-uuid", - sum = "h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=", - version = "v1.0.1", + sum = "h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=", + version = "v1.0.2", ) go_repository( @@ -719,6 +748,43 @@ def go_repositories(): sum = "h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=", version = "v1.0.0", ) + go_repository( + name = "com_github_jcmturner_aescts_v2", + importpath = "github.com/jcmturner/aescts/v2", + sum = "h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=", + version = "v2.0.0", + ) + go_repository( + name = "com_github_jcmturner_dnsutils_v2", + importpath = "github.com/jcmturner/dnsutils/v2", + sum = "h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=", + version = "v2.0.0", + ) + go_repository( + name = "com_github_jcmturner_gofork", + importpath = "github.com/jcmturner/gofork", + sum = "h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=", + version = "v1.0.0", + ) + go_repository( + name = "com_github_jcmturner_goidentity_v6", + importpath = "github.com/jcmturner/goidentity/v6", + sum = "h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=", + version = "v6.0.1", + ) + go_repository( + name = "com_github_jcmturner_gokrb5_v8", + importpath = "github.com/jcmturner/gokrb5/v8", + sum = "h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=", + version = "v8.4.2", + ) + go_repository( + name = "com_github_jcmturner_rpc_v2", + importpath = "github.com/jcmturner/rpc/v2", + sum = "h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=", + version = "v2.0.3", + ) + go_repository( name = "com_github_jmespath_go_jmespath", importpath = "github.com/jmespath/go-jmespath", @@ -738,6 +804,12 @@ def go_repositories(): sum = "h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=", version = "v0.1.0", ) + go_repository( + name = "com_github_jpillora_backoff", + importpath = "github.com/jpillora/backoff", + sum = "h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=", + version = "v1.0.0", + ) go_repository( name = "com_github_json_iterator_go", @@ -776,6 +848,12 @@ def go_repositories(): sum = "h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=", version = "v1.0.0", ) + go_repository( + name = "com_github_klauspost_compress", + importpath = "github.com/klauspost/compress", + sum = "h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=", + version = "v1.11.7", + ) go_repository( name = "com_github_konsorten_go_windows_terminal_sequences", @@ -805,8 +883,14 @@ def go_repositories(): go_repository( name = "com_github_kr_text", importpath = "github.com/kr/text", - sum = "h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=", - version = "v0.1.0", + sum = "h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=", + version = "v0.2.0", + ) + go_repository( + name = "com_github_linkedin_goavro_v2", + importpath = "github.com/linkedin/goavro/v2", + sum = "h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehOGrM=", + version = "v2.9.7", ) go_repository( @@ -821,6 +905,7 @@ def go_repositories(): sum = "h1:TpvdAwDAt1K4ANVOfcihouRdvP+MgAfDWwBuct4l6ZY=", version = "v0.0.0-20160728113105-d5b7844b561a", ) + go_repository( name = "com_github_mattn_go_colorable", importpath = "github.com/mattn/go-colorable", @@ -915,12 +1000,6 @@ def go_repositories(): version = "v0.0.0-20140419014527-cca7078d478f", ) - go_repository( - name = "com_github_nxadm_tail", - importpath = "github.com/nxadm/tail", - sum = "h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=", - version = "v1.4.4", - ) go_repository( name = "com_github_nytimes_gziphandler", importpath = "github.com/NYTimes/gziphandler", @@ -943,14 +1022,14 @@ def go_repositories(): go_repository( name = "com_github_onsi_ginkgo", importpath = "github.com/onsi/ginkgo", - sum = "h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=", - version = "v1.14.1", + sum = "h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=", + version = "v1.11.0", ) go_repository( name = "com_github_onsi_gomega", importpath = "github.com/onsi/gomega", - sum = "h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=", - version = "v1.10.2", + sum = "h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=", + version = "v1.7.0", ) go_repository( @@ -973,6 +1052,12 @@ def go_repositories(): sum = "h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=", version = "v2.0.1+incompatible", ) + go_repository( + name = "com_github_pierrec_lz4", + importpath = "github.com/pierrec/lz4", + sum = "h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A=", + version = "v2.6.0+incompatible", + ) go_repository( name = "com_github_pkg_errors", @@ -1037,6 +1122,18 @@ def go_repositories(): sum = "h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE=", version = "v0.0.0-20160726150825-5bd2802263f2", ) + go_repository( + name = "com_github_rcrowley_go_metrics", + importpath = "github.com/rcrowley/go-metrics", + sum = "h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=", + version = "v0.0.0-20201227073835-cf1acfcdf475", + ) + go_repository( + name = "com_github_riferrei_srclient", + importpath = "github.com/riferrei/srclient", + sum = "h1:uIJhzPXW+suDsEDOZKf4oTZZXTyxtw98cFC70rFzvgU=", + version = "v0.2.1", + ) go_repository( name = "com_github_rogpeppe_fastuuid", @@ -1076,6 +1173,18 @@ def go_repositories(): sum = "h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=", version = "v0.0.0-20170313163322-e2103e2c3529", ) + go_repository( + name = "com_github_shopify_sarama", + importpath = "github.com/Shopify/sarama", + sum = "h1:lOi3SfE6OcFlW9Trgtked2aHNZ2BIG/d6Do+PEUAqqM=", + version = "v1.28.0", + ) + go_repository( + name = "com_github_shopify_toxiproxy", + importpath = "github.com/Shopify/toxiproxy", + sum = "h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=", + version = "v2.1.4+incompatible", + ) go_repository( name = "com_github_shurcool_sanitized_anchor_name", @@ -1161,8 +1270,8 @@ def go_repositories(): go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", - sum = "h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=", - version = "v1.6.1", + sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", + version = "v1.7.0", ) go_repository( name = "com_github_subosito_gotenv", @@ -1202,6 +1311,18 @@ def go_repositories(): sum = "h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648=", version = "v0.0.0-20181204163529-d75b2dcb6bc8", ) + go_repository( + name = "com_github_xdg_scram", + importpath = "github.com/xdg/scram", + sum = "h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=", + version = "v0.0.0-20180814205039-7eeb5667e42c", + ) + go_repository( + name = "com_github_xdg_stringprep", + importpath = "github.com/xdg/stringprep", + sum = "h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=", + version = "v1.0.0", + ) go_repository( name = "com_github_xiang90_probing", @@ -1216,12 +1337,6 @@ def go_repositories(): version = "v0.0.3-0.20170626215501-b2862e3d0a77", ) - go_repository( - name = "com_github_yuin_gopher_lua", - importpath = "github.com/yuin/gopher-lua", - sum = "h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=", - version = "v0.0.0-20191220021717-ab39c6098bdb", - ) go_repository( name = "com_google_cloud_go", importpath = "cloud.google.com/go", @@ -1276,8 +1391,8 @@ def go_repositories(): go_repository( name = "in_gopkg_check_v1", importpath = "gopkg.in/check.v1", - sum = "h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=", - version = "v1.0.0-20190902080502-41f04d3bba15", + sum = "h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=", + version = "v1.0.0-20201130134442-10cb98267c6c", ) go_repository( @@ -1330,8 +1445,8 @@ def go_repositories(): go_repository( name = "in_gopkg_yaml_v3", importpath = "gopkg.in/yaml.v3", - sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=", - version = "v3.0.0-20200313102051-9f266ea9e77c", + sum = "h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=", + version = "v3.0.0-20210107192922-496545a6307b", ) go_repository( name = "io_etcd_go_bbolt", @@ -1420,13 +1535,6 @@ def go_repositories(): version = "v0.22.2", ) - go_repository( - name = "io_opentelemetry_go_otel", - build_file_proto_mode = "disable", - importpath = "go.opentelemetry.io/otel", - sum = "h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E=", - version = "v0.11.0", - ) go_repository( name = "io_rsc_binaryregexp", importpath = "rsc.io/binaryregexp", @@ -1469,8 +1577,8 @@ def go_repositories(): go_repository( name = "org_golang_x_crypto", importpath = "golang.org/x/crypto", - sum = "h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=", - version = "v0.0.0-20200622213623-75b288015ac9", + sum = "h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=", + version = "v0.0.0-20201221181555-eec23a3978ad", ) go_repository( name = "org_golang_x_exp", @@ -1508,8 +1616,8 @@ def go_repositories(): go_repository( name = "org_golang_x_net", importpath = "golang.org/x/net", - sum = "h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=", - version = "v0.0.0-20201110031124-69a78807bb2b", + sum = "h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=", + version = "v0.0.0-20210119194325-5f4716e94777", ) go_repository( name = "org_golang_x_oauth2", @@ -1521,20 +1629,27 @@ def go_repositories(): go_repository( name = "org_golang_x_sync", importpath = "golang.org/x/sync", - sum = "h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=", - version = "v0.0.0-20190911185100-cd5d95a43a6e", + sum = "h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=", + version = "v0.0.0-20201020160332-67f06af15bc9", ) go_repository( name = "org_golang_x_sys", importpath = "golang.org/x/sys", - sum = "h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=", - version = "v0.0.0-20200930185726-fdedc70b468f", + sum = "h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=", + version = "v0.0.0-20201119102817-f84b799fce68", ) + go_repository( + name = "org_golang_x_term", + importpath = "golang.org/x/term", + sum = "h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=", + version = "v0.0.0-20201126162022-7de9c90e9dd1", + ) + go_repository( name = "org_golang_x_text", importpath = "golang.org/x/text", - sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", - version = "v0.3.3", + sum = "h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=", + version = "v0.3.5", ) go_repository( name = "org_golang_x_time", @@ -1552,8 +1667,8 @@ def go_repositories(): go_repository( name = "org_golang_x_xerrors", importpath = "golang.org/x/xerrors", - sum = "h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=", - version = "v0.0.0-20191204190536-9bdfabe68543", + sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=", + version = "v0.0.0-20200804184101-5ec99f83aff1", ) go_repository( diff --git a/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml b/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml index 919d2d7a2b..07ee8106ae 100644 --- a/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml @@ -53,6 +53,21 @@ spec: key: KAFKA_COMMIT_INTERVAL_MS - name: SERVICE_NAME value: api-admin + - name: BEANSTALK_HOSTNAME + valueFrom: + configMapKeyRef: + name: beanstalk-config + key: BEANSTALK_HOSTNAME + - name: BEANSTALK_PORT + valueFrom: + configMapKeyRef: + name: beanstalk-config + key: BEANSTALK_PORT + - name: WEBHOOK_NAME + valueFrom: + configMapKeyRef: + name: webhooks-config + key: NAME livenessProbe: httpGet: path: /actuator/health diff --git a/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml b/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml index 5d9bec820d..c5d22493f5 100644 --- a/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml @@ -31,16 +31,16 @@ spec: env: - name: SERVICE_NAME value: webhook-consumer - - name: REDIS_HOSTNAME + - name: BEANSTALK_HOSTNAME valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_HOSTNAME - - name: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_HOSTNAME + - name: BEANSTALK_PORT valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_PORT - name: WEBHOOK_NAME valueFrom: configMapKeyRef: @@ -64,13 +64,18 @@ spec: - name: SERVICE_NAME valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_HOSTNAME + name: beanstalkd-config + key: BEANSTALK_HOSTNAME - name: SERVICE_PORT valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_PORT + name: beanstalkd-config + key: BEANSTALK_PORT + - name: MAX_BACKOFF_SECONDS + valueFrom: + configMapKeyRef: + name: webhook-config + key: MAX_BACKOFF_SECONDS volumeMounts: - name: provisioning-scripts mountPath: /opt/provisioning @@ -127,16 +132,16 @@ spec: key: KAFKA_COMMIT_INTERVAL_MS - name: SERVICE_NAME value: webhook-publisher - - name: REDIS_HOSTNAME + - name: BEANSTALK_HOSTNAME valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_HOSTNAME - - name: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_HOSTNAME + - name: BEANSTALK_PORT valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_PORT - name: WEBHOOK_NAME valueFrom: configMapKeyRef: diff --git a/infrastructure/helm-chart/charts/beanstalkd/Chart.yaml b/infrastructure/helm-chart/charts/beanstalkd/Chart.yaml new file mode 100644 index 0000000000..5ce8faea3f --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Beanstalkd +name: beanstalkd +version: 1.0 diff --git a/infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml b/infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml new file mode 100644 index 0000000000..5e98901988 --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: beanstalk + namespace: {{ .Values.global.namespace }} +spec: + type: ClusterIP + ports: + - name: client + port: {{ .Values.port }} + targetPort: {{ .Values.port }} + - name: exporter + port: {{ .Values.prometheusExporterPort }} + targetPort: {{ .Values.prometheusExporterPort }} + selector: + app: beanstalkd diff --git a/infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml b/infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml new file mode 100644 index 0000000000..c7563570af --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: beanstalkd + namespace: {{ .Values.global.namespace}} +spec: + serviceName: beanstalkd + replicas: 1 + selector: + matchLabels: + app: beanstalkd + template: + metadata: + labels: + app: beanstalkd + spec: + containers: + - name: beanstalk + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + ports: + - containerPort: {{ .Values.port }} + name: client + - name: beanstalk-exporter + image: "{{ .Values.prometheusExporterImage }}:{{ .Values.prometheusExporterImageTag }}" + resources: + requests: + cpu: 100m + memory: 100Mi + ports: + - containerPort: {{ .Values.prometheusExporterPort }} + name: exporter + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 1Gi diff --git a/infrastructure/helm-chart/charts/beanstalkd/values.yaml b/infrastructure/helm-chart/charts/beanstalkd/values.yaml new file mode 100644 index 0000000000..3d5468c435 --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/values.yaml @@ -0,0 +1,8 @@ +enabled: true +image: schickling/beanstalkd +imageTag: latest +resources: {} +port: 11300 +prometheusExporterImage: messagebird/beanstalkd_exporter +prometheusExporterImageTag: latest +prometheusExporterPort: 8080 diff --git a/infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml b/infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml new file mode 100644 index 0000000000..e16f2f2879 --- /dev/null +++ b/infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: beanstalk-config + namespace: {{ .Values.global.namespace }} +data: + BEANSTALK_HOSTNAME: {{ .Values.beanstalk.hostname }} + BEANSTALK_PORT: "{{ .Values.beanstalk.port }}" diff --git a/infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml b/infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml deleted file mode 100644 index 91182856ab..0000000000 --- a/infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: redis-config - namespace: {{ .Values.global.namespace }} -data: - REDIS_HOSTNAME: {{ .Values.redis.hostname }} - REDIS_PORT: "{{ .Values.redis.port }}" diff --git a/infrastructure/helm-chart/charts/prerequisites/values.yaml b/infrastructure/helm-chart/charts/prerequisites/values.yaml index 42fa8da1e8..90f41358c7 100644 --- a/infrastructure/helm-chart/charts/prerequisites/values.yaml +++ b/infrastructure/helm-chart/charts/prerequisites/values.yaml @@ -3,6 +3,6 @@ kafka: zookeeper: "zookeeper:2181" schemaRegistryUrl: "http://schema-registry:8081" commitInterval: 1000 -redis: - hostname: "redis-cluster" - port: 6379 +beanstalk: + hostname: "beanstalk" + port: 11300 \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/Chart.yaml b/infrastructure/helm-chart/charts/redis/Chart.yaml deleted file mode 100644 index 5e07ff4c78..0000000000 --- a/infrastructure/helm-chart/charts/redis/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Redis -name: redis -version: 1.0 \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/templates/configmap.yaml b/infrastructure/helm-chart/charts/redis/templates/configmap.yaml deleted file mode 100644 index 01abc80ee8..0000000000 --- a/infrastructure/helm-chart/charts/redis/templates/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: redis-cluster - namespace: {{ .Values.global.namespace }} -data: - update-node.sh: | - #!/bin/sh - REDIS_NODES="/data/nodes.conf" - sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${REDIS_NODES} - exec "$@" - redis.conf: |+ - cluster-enabled no - cluster-require-full-coverage no - cluster-node-timeout 15000 - cluster-config-file /data/nodes.conf - cluster-migration-barrier 1 - appendonly yes - protected-mode no \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/templates/service.yaml b/infrastructure/helm-chart/charts/redis/templates/service.yaml deleted file mode 100644 index 0df88d88c2..0000000000 --- a/infrastructure/helm-chart/charts/redis/templates/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: redis-cluster - namespace: {{ .Values.global.namespace }} -spec: - type: ClusterIP - ports: - - port: 6379 - targetPort: 6379 - name: client - - port: 16379 - targetPort: 16379 - name: gossip - selector: - app: redis-cluster \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/templates/statefulset.yaml b/infrastructure/helm-chart/charts/redis/templates/statefulset.yaml deleted file mode 100644 index 843ca11ca2..0000000000 --- a/infrastructure/helm-chart/charts/redis/templates/statefulset.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: redis-cluster - namespace: {{ .Values.global.namespace }} -spec: - serviceName: redis-cluster - replicas: 1 - selector: - matchLabels: - app: redis-cluster - template: - metadata: - labels: - app: redis-cluster - spec: - containers: - - name: redis - image: "{{ .Values.image }}:{{ .Values.imageTag }}" - ports: - - containerPort: 6379 - name: client - - containerPort: 16379 - name: gossip - command: ["/conf/update-node.sh", "redis-server", "/conf/redis.conf"] - env: - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - volumeMounts: - - name: conf - mountPath: /conf - readOnly: false - - name: data - mountPath: /data - readOnly: false - volumes: - - name: conf - configMap: - name: redis-cluster - defaultMode: 0755 - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 1Gi \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/values.yaml b/infrastructure/helm-chart/charts/redis/values.yaml deleted file mode 100644 index a1b8ae4caf..0000000000 --- a/infrastructure/helm-chart/charts/redis/values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -enabled: true -image: redis -imageTag: 5.0.1-alpine -resources: {} diff --git a/infrastructure/tools/prometheus/values.yaml b/infrastructure/tools/prometheus/values.yaml index c7d8b6d14f..0003857c98 100644 --- a/infrastructure/tools/prometheus/values.yaml +++ b/infrastructure/tools/prometheus/values.yaml @@ -21,6 +21,10 @@ prometheus: paths: ['/prometheus'] prometheusSpec: routePrefix: /prometheus + additionalScrapeConfigs: + - job_name: beanstalkd_exporter + static_configs: + - targets: ['beanstalk:8080'] additionalServiceMonitors: - name: "spring-apps" selector: diff --git a/maven_install.json b/maven_install.json index 47277aeaa7..6bac8d9d74 100644 --- a/maven_install.json +++ b/maven_install.json @@ -1,6 +1,6 @@ { "dependency_tree": { - "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 669563076, + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 401678455, "conflict_resolution": { "com.fasterxml.jackson.core:jackson-annotations:2.10.0": "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "com.fasterxml.jackson.core:jackson-core:2.10.0": "com.fasterxml.jackson.core:jackson-core:2.11.4", @@ -222,6 +222,32 @@ "sha256": "6b83846f2ff61d0aaa66997b64b883ec7b65cf13b50a4d7f58250996d429be2e", "url": "https://repo1.maven.org/maven2/com/damnhandy/handy-uri-templates/2.1.8/handy-uri-templates-2.1.8.jar" }, + { + "coord": "com.dinstone:beanstalkc:2.3.0", + "dependencies": [ + "org.slf4j:slf4j-api:1.7.30", + "org.slf4j:slf4j-api:jar:1.7.30", + "org.apache.mina:mina-core:2.1.3" + ], + "directDependencies": [ + "org.apache.mina:mina-core:2.1.3", + "org.slf4j:slf4j-api:jar:1.7.30" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar", + "https://repo1.maven.org/maven2/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar", + "https://jitpack.io/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar" + ], + "sha256": "1e4ff30499ae4229b0aca779ad90e184fa9fbcbbb3ad0bad4fb8beff2ca86b1b", + "url": "https://repo1.maven.org/maven2/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar" + }, { "coord": "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "dependencies": [], @@ -2036,6 +2062,7 @@ "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4", "com.kjetland:mbknor-jackson-jsonschema_2.12:1.0.39", "org.jetbrains.kotlin:kotlin-script-runtime:1.3.50", + "io.netty:netty-transport:4.1.48.Final", "org.ow2.asm:asm-analysis:9.0", "commons-validator:commons-validator:1.6", "javax.xml.bind:jaxb-api:2.3.1", @@ -2083,11 +2110,11 @@ "com.google.re2j:re2j:1.3", "javax.websocket:javax.websocket-client-api:1.0", "org.eclipse.jetty:jetty-xml:9.4.39.v20210325", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", "com.google.code.gson:gson:2.8.6", "com.fasterxml.jackson.core:jackson-databind:2.11.4", "com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4", + "io.netty:netty-buffer:4.1.48.Final", "io.confluent:common-metrics:5.5.1", "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.71", "io.confluent:kafka-protobuf-provider:5.5.1", @@ -2095,7 +2122,6 @@ "org.eclipse.jetty.websocket:websocket-client:9.4.39.v20210325", "org.glassfish.jersey.core:jersey-server:2.30", "org.eclipse.jetty.websocket:websocket-servlet:9.4.39.v20210325", - "io.netty:netty-codec:4.1.51.Final", "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.71", "org.glassfish.hk2:hk2-utils:2.6.1", "org.apache.avro:avro:1.10.0", @@ -2106,18 +2132,17 @@ "com.google.errorprone:error_prone_annotations:2.3.4", "org.eclipse.jetty:jetty-server:9.4.39.v20210325", "jakarta.annotation:jakarta.annotation-api:1.3.5", - "io.netty:netty-resolver:4.1.51.Final", "org.scala-lang.modules:scala-java8-compat_2.12:0.9.0", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", "org.eclipse.jetty.websocket:javax-websocket-client-impl:9.4.39.v20210325", + "io.netty:netty-resolver:4.1.48.Final", "org.jetbrains.kotlin:kotlin-stdlib-common:1.3.71", "org.jetbrains.kotlin:kotlin-scripting-jvm:1.3.50", "org.apache.yetus:audience-annotations:0.5.0", + "io.netty:netty-common:4.1.48.Final", "org.json:json:20201115", "org.scala-lang:scala-reflect:2.12.10", "com.damnhandy:handy-uri-templates:2.1.8", - "io.netty:netty-transport:4.1.51.Final", "com.yammer.metrics:metrics-core:2.2.0", "org.glassfish.jersey.ext:jersey-bean-validation:2.30", "org.jetbrains.kotlin:kotlin-stdlib:1.3.71", @@ -2132,6 +2157,7 @@ "org.eclipse.jetty:jetty-jaas:9.4.24.v20191120", "org.hibernate.validator:hibernate-validator:6.0.17.Final", "org.eclipse.jetty:jetty-client:9.4.39.v20210325", + "io.netty:netty-handler:4.1.48.Final", "io.confluent:common-utils:5.5.1", "javax.annotation:javax.annotation-api:1.3.2", "io.confluent:common-config:5.5.1", @@ -2145,10 +2171,10 @@ "com.google.guava:guava:29.0-jre", "org.glassfish.jersey.containers:jersey-container-servlet:2.30", "org.eclipse.jetty.websocket:websocket-common:9.4.39.v20210325", + "io.netty:netty-codec:4.1.48.Final", "com.fasterxml:classmate:1.3.4", "org.eclipse.jetty:jetty-servlet:9.4.39.v20210325", "org.eclipse.jetty:jetty-jndi:9.4.39.v20210325", - "io.netty:netty-common:4.1.51.Final", "org.glassfish:jakarta.el:3.0.3", "io.confluent:kafka-schema-registry-client:5.5.1", "jakarta.activation:jakarta.activation-api:1.2.2", @@ -2531,39 +2557,6 @@ "sha256": "5b5f84f4397c54ab4f6267f95b3c2186d32a5562e6704a0a581401b3ee3a2d0d", "url": "https://repo1.maven.org/maven2/io/jsonwebtoken/jjwt-jackson/0.10.7/jjwt-jackson-0.10.7.jar" }, - { - "coord": "io.lettuce:lettuce-core:5.3.3.RELEASE", - "dependencies": [ - "org.reactivestreams:reactive-streams:1.0.3", - "io.projectreactor:reactor-core:3.3.9.RELEASE", - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final" - ], - "directDependencies": [ - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.projectreactor:reactor-core:3.3.9.RELEASE" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar", - "https://jitpack.io/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar" - ], - "sha256": "0cd01a1cbe881dc7f7b72118e274eaff8cac3865f2258d3389dbe436fb498841", - "url": "https://repo1.maven.org/maven2/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar" - }, { "coord": "io.micrometer:micrometer-core:1.6.6", "dependencies": [ @@ -2618,40 +2611,12 @@ "url": "https://repo1.maven.org/maven2/io/micrometer/micrometer-registry-prometheus/1.6.5/micrometer-registry-prometheus-1.6.5.jar" }, { - "coord": "io.netty:netty-buffer:4.1.51.Final", - "dependencies": [ - "io.netty:netty-common:4.1.51.Final" - ], - "directDependencies": [ - "io.netty:netty-common:4.1.51.Final" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar" - ], - "sha256": "c3c3b710e1b5a8df3d60cd4602e0a743481d5e609e4aa852fa2629e4e412d245", - "url": "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar" - }, - { - "coord": "io.netty:netty-codec:4.1.51.Final", + "coord": "io.netty:netty-buffer:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final" ], "exclusions": [ "*:jline", @@ -2667,50 +2632,51 @@ "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar" ], - "sha256": "ff741aaa35f7048a6be7c700aa4851bf643917648ea5b7c0cbada2f3848c2bee", - "url": "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar" + "sha256": "7efc8f98224c703ef09a409e5ddffbe14f5b4b6f527d3836c1647b4d9eff8cec", + "url": "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-common:4.1.51.Final", - "dependencies": [], - "directDependencies": [], + "coord": "io.netty:netty-codec:4.1.48.Final", + "dependencies": [ + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final" + ], + "directDependencies": [ + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final" + ], "exclusions": [ - "ch.qos.logback:logback-classic", + "javax.jms:jms", + "org.slf4j:slf4j-log4j12", + "junit:junit", "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" + "com.sun.jmx:jmxri", + "com.sun.jdmk:jmxtools", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar" ], - "sha256": "110e06515f43913a2bbac23e1aa78b7f59ae09d466b00af5fcf399a4f9af1b6b", - "url": "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar" + "sha256": "81b4c316163a591b4f74fd2dc23a3ea45359cb817d0a9c4fc7f37dc9edfdbea8", + "url": "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-handler:4.1.51.Final", - "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final" - ], - "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final" - ], + "coord": "io.netty:netty-common:4.1.48.Final", + "dependencies": [], + "directDependencies": [], "exclusions": [ "*:jline", "*:netty", @@ -2725,51 +2691,87 @@ "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar" ], - "sha256": "4461970f04f4d5eb9112ad94255ce1987394ce64de6c3c87690bf0865c936258", - "url": "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar" + "sha256": "e44a2369566fd1fa8a0f30b12e2801de8fb405b9d1fa3894a58b6262065a9916", + "url": "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-resolver:4.1.51.Final", + "coord": "io.netty:netty-handler:4.1.48.Final", "dependencies": [ - "io.netty:netty-common:4.1.51.Final" + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-codec:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-common:4.1.51.Final" + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-codec:4.1.48.Final" ], "exclusions": [ + "javax.jms:jms", + "org.slf4j:slf4j-log4j12", + "junit:junit", + "org.springframework.boot:spring-boot-starter-tomcat", + "com.sun.jmx:jmxri", + "com.sun.jdmk:jmxtools", "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar" + ], + "sha256": "757f83c7891ad2ebad209f02d8dbca0121e03f7062c2d4ec9d00eba1a0d403d5", + "url": "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar" + }, + { + "coord": "io.netty:netty-resolver:4.1.48.Final", + "dependencies": [ + "io.netty:netty-common:4.1.48.Final" + ], + "directDependencies": [ + "io.netty:netty-common:4.1.48.Final" + ], + "exclusions": [ + "org.slf4j:slf4j-log4j12", "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" + "log4j:log4j" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar" ], - "sha256": "c8a77765e481fbf5906c596eb441de49096b354bcae0356b7404ac5e96399350", - "url": "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar" + "sha256": "fb125914398ebef821def3dbb1642f9f360f39d182f00149ef3db845ebf06ad2", + "url": "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar" }, { "coord": "io.netty:netty-transport-native-epoll:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final" ], "exclusions": [ @@ -2798,15 +2800,15 @@ { "coord": "io.netty:netty-transport-native-unix-common:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final" ], "exclusions": [ "javax.jms:jms", @@ -2828,31 +2830,32 @@ "url": "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.48.Final/netty-transport-native-unix-common-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-transport:4.1.51.Final", + "coord": "io.netty:netty-transport:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final" + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final" ], "exclusions": [ - "ch.qos.logback:logback-classic", + "org.slf4j:slf4j-log4j12", "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" + "log4j:log4j" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar" ], - "sha256": "e5be259f35a246bf504ad93ea8f5df31872b5abebfb751380eab95d5dc840d44", - "url": "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar" + "sha256": "6b4ba9e09a8e060bad2540845491b5fa1ca73614d157860e657f4027c91e72fd", + "url": "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar" }, { "coord": "io.opencensus:opencensus-api:0.24.0", @@ -2909,29 +2912,6 @@ "sha256": "7155273bbb1ed3d477ea33cf19d7bbc0b285ff395f43b29ae576722cf247000f", "url": "https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.24.0/opencensus-contrib-http-util-0.24.0.jar" }, - { - "coord": "io.projectreactor:reactor-core:3.3.9.RELEASE", - "dependencies": [ - "org.reactivestreams:reactive-streams:1.0.3" - ], - "directDependencies": [ - "org.reactivestreams:reactive-streams:1.0.3" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar", - "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar", - "https://jitpack.io/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar" - ], - "sha256": "2e72796bf56a03e767a5fa1e0e1027b5c9b3737489922ce28138349796b2ed19", - "url": "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar" - }, { "coord": "io.prometheus:simpleclient:0.9.0", "dependencies": [], @@ -4043,23 +4023,23 @@ "coord": "org.apache.curator:curator-test:4.2.0", "dependencies": [ "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava", + "io.netty:netty-transport:4.1.48.Final", "com.google.j2objc:j2objc-annotations:1.3", "com.google.code.findbugs:jsr305:3.0.2", "org.slf4j:slf4j-api:1.7.30", "org.apache.zookeeper:zookeeper:3.5.8", "log4j:log4j:1.2.17", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", - "io.netty:netty-codec:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", "com.google.errorprone:error_prone_annotations:2.3.4", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", + "io.netty:netty-resolver:4.1.48.Final", "org.apache.yetus:audience-annotations:0.5.0", - "io.netty:netty-transport:4.1.51.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-handler:4.1.48.Final", "com.google.guava:failureaccess:1.0.1", "com.google.guava:guava:29.0-jre", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-codec:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final", "org.checkerframework:checker-qual:2.11.1" ], @@ -4328,6 +4308,7 @@ { "coord": "org.apache.kafka:kafka_2.12:5.5.1-ccs", "dependencies": [ + "io.netty:netty-transport:4.1.48.Final", "org.apache.kafka:kafka-clients:5.5.1-ccs", "com.thoughtworks.paranamer:paranamer:2.8", "com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.10.2", @@ -4340,20 +4321,19 @@ "org.apache.zookeeper:zookeeper:3.5.8", "org.lz4:lz4-java:1.7.1", "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", "com.fasterxml.jackson.core:jackson-databind:2.11.4", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", "org.scala-lang.modules:scala-java8-compat_2.12:0.9.0", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", + "io.netty:netty-resolver:4.1.48.Final", "org.apache.yetus:audience-annotations:0.5.0", + "io.netty:netty-common:4.1.48.Final", "org.scala-lang:scala-reflect:2.12.10", - "io.netty:netty-transport:4.1.51.Final", "com.yammer.metrics:metrics-core:2.2.0", + "io.netty:netty-handler:4.1.48.Final", "org.scala-lang:scala-library:2.12.10", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-codec:4.1.48.Final", "com.github.luben:zstd-jni:1.4.5-2", "commons-cli:commons-cli:1.4", "org.scala-lang.modules:scala-collection-compat_2.12:2.1.3", @@ -4571,6 +4551,29 @@ "sha256": "073381087a3014cc66859779141a4627e239b2d019676d9800411172b2c0bee6", "url": "https://repo1.maven.org/maven2/org/apache/lucene/lucene-sandbox/8.7.0/lucene-sandbox-8.7.0.jar" }, + { + "coord": "org.apache.mina:mina-core:2.1.3", + "dependencies": [ + "org.slf4j:slf4j-api:1.7.30" + ], + "directDependencies": [ + "org.slf4j:slf4j-api:1.7.30" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar", + "https://repo1.maven.org/maven2/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar", + "https://jitpack.io/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar" + ], + "sha256": "28bfef56fb8fedeee0ddc1cb6d7297a6c7dd04b3299b50968a77216c25593941", + "url": "https://repo1.maven.org/maven2/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar" + }, { "coord": "org.apache.velocity:velocity-engine-core:2.2", "dependencies": [ @@ -4650,26 +4653,26 @@ { "coord": "org.apache.zookeeper:zookeeper:3.5.8", "dependencies": [ + "io.netty:netty-transport:4.1.48.Final", "org.slf4j:slf4j-api:1.7.30", "log4j:log4j:1.2.17", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", + "io.netty:netty-resolver:4.1.48.Final", "org.apache.yetus:audience-annotations:0.5.0", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-handler:4.1.48.Final", + "io.netty:netty-codec:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final" ], "directDependencies": [ "org.slf4j:slf4j-api:1.7.30", "log4j:log4j:1.2.17", "io.netty:netty-transport-native-epoll:4.1.48.Final", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", - "org.apache.yetus:audience-annotations:0.5.0" + "org.apache.yetus:audience-annotations:0.5.0", + "io.netty:netty-handler:4.1.48.Final" ], "exclusions": [ "javax.jms:jms", @@ -6867,25 +6870,6 @@ "sha256": "2836e954823bfcbad45e78c18896e3d01058e6f643749810c608b7005ee7b2fa", "url": "https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.10/lombok-1.18.10.jar" }, - { - "coord": "org.reactivestreams:reactive-streams:1.0.3", - "dependencies": [], - "directDependencies": [], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "https://jitpack.io/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" - ], - "sha256": "1dee0481072d19c929b623e155e14d2f6085dc011529a0a0dbefc84cf571d865", - "url": "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" - }, { "coord": "org.reflections:reflections:0.9.12", "dependencies": [ @@ -7670,107 +7654,6 @@ "sha256": "2e46ae8796df9ca1b4ad74eab608b19f771255321e7d9fafb64561e7e030869e", "url": "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot/2.4.5/spring-boot-2.4.5.jar" }, - { - "coord": "org.springframework.data:spring-data-commons:2.3.3.RELEASE", - "dependencies": [ - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6", - "org.springframework:spring-jcl:5.3.6" - ], - "directDependencies": [ - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar", - "https://jitpack.io/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar" - ], - "sha256": "f53742d93faf5dfb63318c173be4f5443dbba804753ce811cdb6be3260b399bc", - "url": "https://repo1.maven.org/maven2/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar" - }, - { - "coord": "org.springframework.data:spring-data-keyvalue:2.3.3.RELEASE", - "dependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-jcl:5.3.6", - "org.springframework:spring-context:5.3.6", - "org.springframework:spring-expression:5.3.6", - "org.springframework:spring-core:5.3.6", - "org.springframework.data:spring-data-commons:2.3.3.RELEASE", - "org.springframework:spring-aop:5.3.6" - ], - "directDependencies": [ - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-context:5.3.6", - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.springframework.data:spring-data-commons:2.3.3.RELEASE" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar", - "https://jitpack.io/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar" - ], - "sha256": "e5e301d378cfacf3941c1e063c03134a802d5604da987d52391461db1b72d37c", - "url": "https://repo1.maven.org/maven2/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar" - }, - { - "coord": "org.springframework.data:spring-data-redis:2.3.3.RELEASE", - "dependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-jcl:5.3.6", - "org.springframework:spring-context:5.3.6", - "org.springframework:spring-context-support:5.3.6", - "org.springframework:spring-expression:5.3.6", - "org.springframework:spring-oxm:5.2.8.RELEASE", - "org.springframework:spring-core:5.3.6", - "org.springframework.data:spring-data-commons:2.3.3.RELEASE", - "org.springframework:spring-aop:5.3.6", - "org.springframework.data:spring-data-keyvalue:2.3.3.RELEASE" - ], - "directDependencies": [ - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-context-support:5.3.6", - "org.springframework:spring-oxm:5.2.8.RELEASE", - "org.springframework:spring-aop:5.3.6", - "org.springframework.data:spring-data-keyvalue:2.3.3.RELEASE" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar", - "https://jitpack.io/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar" - ], - "sha256": "d28e3914d8345a6d30d7292b710bc5b74d127fa2ce89588e9ff0e7a28905f11a", - "url": "https://repo1.maven.org/maven2/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar" - }, { "coord": "org.springframework.retry:spring-retry:1.2.5.RELEASE", "dependencies": [ @@ -8098,32 +7981,6 @@ "sha256": "7f3491e73a48781ae39d93cb7b01b88c7d6fa802a8184d4a5d82ee36804289c1", "url": "https://repo1.maven.org/maven2/org/springframework/spring-messaging/5.3.6/spring-messaging-5.3.6.jar" }, - { - "coord": "org.springframework:spring-oxm:5.2.8.RELEASE", - "dependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6", - "org.springframework:spring-jcl:5.3.6" - ], - "directDependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar", - "https://jitpack.io/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar" - ], - "sha256": "0fdb104a00ace520d0f75adf698867d05997b647a28f079811cba8fa2742200d", - "url": "https://repo1.maven.org/maven2/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar" - }, { "coord": "org.springframework:spring-test:5.3.6", "dependencies": [ @@ -8148,32 +8005,6 @@ "sha256": "b85bc653b7eda0488f68a18257b5a3ccb61b5ef24b32af48cded0953d6ec76b8", "url": "https://repo1.maven.org/maven2/org/springframework/spring-test/5.3.6/spring-test-5.3.6.jar" }, - { - "coord": "org.springframework:spring-tx:5.2.8.RELEASE", - "dependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6", - "org.springframework:spring-jcl:5.3.6" - ], - "directDependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar", - "https://jitpack.io/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar" - ], - "sha256": "df2aeb728d5c95938c5b301175b1d48b3281ef56bd17b13bd010555cc954a31f", - "url": "https://repo1.maven.org/maven2/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar" - }, { "coord": "org.springframework:spring-web:5.3.6", "dependencies": [ From 915a9364e53ca3443c0b2b27b14463d3f3502756 Mon Sep 17 00:00:00 2001 From: AudreyKj <38159391+AudreyKj@users.noreply.github.com> Date: Mon, 3 May 2021 15:22:15 +0200 Subject: [PATCH 23/28] [#1689] fixed conversation counter optimizing filter use (#1697) --- .../Inbox/ConversationListHeader/index.tsx | 7 +++++-- .../pages/Inbox/ConversationsFilter/index.tsx | 20 ------------------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx index 40e3394d0e..fa7899678d 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx @@ -25,6 +25,7 @@ const mapStateToProps = (state: StateModel) => ({ user: state.data.user, currentFilter: state.data.conversations.filtered.currentFilter || {}, totalConversations: state.data.conversations.all.paginationData.total, + filteredPaginationData: state.data.conversations.filtered.paginationData, }); const connector = connect(mapStateToProps, mapDispatchToProps); @@ -68,9 +69,11 @@ const ConversationListHeader = (props: ConversationListHeaderProps) => { }; const InboxConversationCount = () => { - const {totalConversations} = props; + const {totalConversations, filteredPaginationData} = props; - return
{`Inbox (${totalConversations})`}
; + return ( +
{`Inbox (${filteredPaginationData.filteredTotal ?? totalConversations})`}
+ ); }; const toggleFilter = () => { diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx index 81edd65d57..7d2eb79871 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx @@ -13,7 +13,6 @@ const mapStateToProps = (state: StateModel) => { return { conversationsFilter: state.data.conversations.filtered.currentFilter, isFilterActive: isFilterActive(state), - filteredPaginationData: state.data.conversations.filtered.paginationData, conversations: allConversations(state), }; }; @@ -33,7 +32,6 @@ const ConversationsFilter = (props: ConversationsFilterProps) => { const closedButton = useRef(null); useEffect(() => { - itemsCount(); currentStateFilter(); }), [props.conversations]; @@ -58,26 +56,8 @@ const ConversationsFilter = (props: ConversationsFilterProps) => { setFilter(newFilter); }; - const itemsCount = () => { - const {filteredPaginationData} = props; - - if ( - filteredPaginationData.filteredTotal !== undefined && - filteredPaginationData.filteredTotal !== filteredPaginationData.total - ) { - return ( -
- {`Filtered: ${filteredPaginationData.filteredTotal} Total: ${props.conversations.length}`} -
- ); - } - - return
 
; - }; - return (
- {itemsCount()}
From f18ddc75a19c20b5635e177b93bb2fc7c03f2648 Mon Sep 17 00:00:00 2001 From: Pascal Holy <54705263+pascal-airy@users.noreply.github.com> Date: Mon, 3 May 2021 15:58:11 +0200 Subject: [PATCH 24/28] [#1698] Webhook config error (#1699) Fixes #1698 --- .../installation/configuration.md | 2 ++ .../api-admin/templates/deployment.yaml | 5 ----- .../charts/webhook/templates/deployments.yaml | 20 ++++++++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/docs/getting-started/installation/configuration.md b/docs/docs/getting-started/installation/configuration.md index 3b9433113d..591cf5976d 100644 --- a/docs/docs/getting-started/installation/configuration.md +++ b/docs/docs/getting-started/installation/configuration.md @@ -74,6 +74,8 @@ cluster and Redis. - `integration` - `webhook` - `name` set this to the name of your webhook integration + - `maxBackoff` set this to the maximum number of seconds the webhook should + wait between retries with exponential backoff - `media` - `resolver` - `s3Key` set this to your AWS S3 access key id diff --git a/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml b/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml index 07ee8106ae..7e62ba1eee 100644 --- a/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml @@ -63,11 +63,6 @@ spec: configMapKeyRef: name: beanstalk-config key: BEANSTALK_PORT - - name: WEBHOOK_NAME - valueFrom: - configMapKeyRef: - name: webhooks-config - key: NAME livenessProbe: httpGet: path: /actuator/health diff --git a/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml b/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml index c5d22493f5..3ca65588d0 100644 --- a/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml @@ -41,11 +41,26 @@ spec: configMapKeyRef: name: beanstalk-config key: BEANSTALK_PORT + - name: KAFKA_BROKERS + valueFrom: + configMapKeyRef: + name: kafka-config + key: KAFKA_BROKERS + - name: KAFKA_SCHEMA_REGISTRY_URL + valueFrom: + configMapKeyRef: + name: kafka-config + key: KAFKA_SCHEMA_REGISTRY_URL - name: WEBHOOK_NAME valueFrom: configMapKeyRef: name: "{{ .Values.component }}" key: name + - name: MAX_BACKOFF_SECONDS + valueFrom: + configMapKeyRef: + name: integration-webhook + key: maxBackoff livenessProbe: httpGet: path: /health @@ -71,11 +86,6 @@ spec: configMapKeyRef: name: beanstalkd-config key: BEANSTALK_PORT - - name: MAX_BACKOFF_SECONDS - valueFrom: - configMapKeyRef: - name: webhook-config - key: MAX_BACKOFF_SECONDS volumeMounts: - name: provisioning-scripts mountPath: /opt/provisioning From c99206802b5240f8de51b9f8aeabf0e4d327b308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 May 2021 16:35:00 +0200 Subject: [PATCH 25/28] Bump webpack from 5.36.1 to 5.36.2 (#1692) Bumps [webpack](https://github.com/webpack/webpack) from 5.36.1 to 5.36.2. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.36.1...v5.36.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 14326e08b6..f38cddda1c 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "terser-webpack-plugin": "^5.1.1", "typescript": "3.7.4", "url-loader": "^4.1.1", - "webpack": "^5.36.1", + "webpack": "^5.36.2", "webpack-bundle-analyzer": "^4.4.1", "webpack-cli": "^4.6.0", "webpack-dev-server": "^3.11.2" diff --git a/yarn.lock b/yarn.lock index f04622c655..c45a4f0805 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7720,10 +7720,10 @@ webpack-sources@^2.1.1: source-list-map "^2.0.1" source-map "^0.6.1" -webpack@^5.36.1: - version "5.36.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.36.1.tgz#d82bad3384f84ed45a8de3844c31730f56361ab7" - integrity sha512-2u25a82T+6quAxSlzEpN/R/RICwt20ONU3z3Ko05S8KVH9FXILcBYb2hD/rQtZT5y7lRAIsIIs05pdndY7ourQ== +webpack@^5.36.2: + version "5.36.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.36.2.tgz#6ef1fb2453ad52faa61e78d486d353d07cca8a0f" + integrity sha512-XJumVnnGoH2dV+Pk1VwgY4YT6AiMKpVoudUFCNOXMIVrEKPUgEwdIfWPjIuGLESAiS8EdIHX5+TiJz/5JccmRg== dependencies: "@types/eslint-scope" "^3.7.0" "@types/estree" "^0.0.47" From 625eb7d9b96be10bcdee162dcb5e46c04d4938e9 Mon Sep 17 00:00:00 2001 From: Christoph Proeschel Date: Tue, 4 May 2021 10:51:17 +0200 Subject: [PATCH 26/28] [#1518] Add OIDC authentication backend (#1623) --- BUILD | 3 + WORKSPACE | 2 + .../api/config/ClientConfigController.java | 5 +- .../config/ClientConfigResponsePayload.java | 2 + .../communication/SendMessageController.java | 9 +- .../core/api/websocket/WebSocketConfig.java | 60 --- cli/pkg/cmd/config/config.go | 6 +- cli/pkg/cmd/config/parser.go | 31 +- cli/pkg/cmd/create/helm.go | 3 - cli/pkg/workspace/template/airy.yaml | 2 + docs/docs/api/authentication.md | 66 ++- .../installation/configuration.md | 2 + .../apps/charts/api/templates/security.yaml | 1 + .../helm-chart/templates/ingress.yaml | 21 + lib/java/spring/auth/BUILD | 7 +- .../java/co/airy/spring/auth/AuthConfig.java | 60 ++- .../co/airy/spring/auth/PrincipalAccess.java | 38 ++ .../airy/spring/auth/oidc/ClientConfig.java | 41 ++ .../spring/auth/oidc/CommonProviders.java | 90 ++++ .../airy/spring/auth/oidc/ConfigProvider.java | 83 ++++ .../co/airy/spring/auth/oidc/EmailFilter.java | 58 +++ .../airy/spring/auth/oidc/UserProperties.java | 58 +++ .../co/airy/spring/auth/oidc/UserService.java | 52 +++ .../auth/oidc/github/EmailsResponse.java | 10 + .../spring/auth/oidc/github/GithubApi.java | 49 +++ .../co/airy/spring/auth/session/AiryAuth.java | 53 +++ .../airy/spring/auth/session/AuthCookie.java | 14 + .../CookieSecurityContextRepository.java | 117 ++++++ .../java/co/airy/spring/auth/session/Jwt.java | 65 +++ .../airy/spring/auth/session/UserProfile.java | 34 ++ .../{ => token}/AuthenticationFilter.java | 23 +- .../co/airy/spring/auth/token/TokenAuth.java | 50 +++ ...ilterTest.java => AuthenticationTest.java} | 12 +- .../java/co/airy/spring/auth/NoAuthTest.java | 30 ++ .../java/co/airy/spring/auth/OidcTest.java | 49 +++ .../Controller.java} | 10 +- maven_install.json | 389 +++++++++++++++++- 37 files changed, 1477 insertions(+), 128 deletions(-) create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java rename lib/java/spring/auth/src/main/java/co/airy/spring/auth/{ => token}/AuthenticationFilter.java (54%) create mode 100644 lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java rename lib/java/spring/auth/src/test/java/co/airy/spring/auth/{JwtAuthenticationFilterTest.java => AuthenticationTest.java} (87%) create mode 100644 lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java create mode 100644 lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java rename lib/java/spring/auth/src/test/java/co/airy/spring/auth/{TestApp.java => test_app/Controller.java} (79%) diff --git a/BUILD b/BUILD index 20454c9891..6f024f4997 100644 --- a/BUILD +++ b/BUILD @@ -136,9 +136,12 @@ java_library( java_library( name = "springboot_security", exports = [ + "@maven//:org_springframework_boot_spring_boot_starter_oauth2_client", "@maven//:org_springframework_boot_spring_boot_starter_security", + "@maven//:org_springframework_security_oauth_spring_security_oauth2", "@maven//:org_springframework_security_spring_security_config", "@maven//:org_springframework_security_spring_security_core", + "@maven//:org_springframework_security_spring_security_oauth2_core", "@maven//:org_springframework_security_spring_security_web", ], ) diff --git a/WORKSPACE b/WORKSPACE index 40d940ed25..271e190dc1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -77,6 +77,8 @@ maven_install( "org.springframework.boot:spring-boot-starter-web:2.4.5", "org.springframework.boot:spring-boot-starter-websocket:2.4.5", "org.springframework.boot:spring-boot-starter-security:2.4.5", + "org.springframework.boot:spring-boot-starter-oauth2-client:2.4.5", + "org.springframework.security.oauth:spring-security-oauth2:2.4.1.RELEASE", "org.springframework.retry:spring-retry:1.2.5.RELEASE", "org.springframework:spring-aop:4.1.4.RELEASE", "org.springframework:spring-context-support:5.3.6", diff --git a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java index 5c4d35c666..c74a7c1af6 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java @@ -1,6 +1,8 @@ package co.airy.core.api.config; +import co.airy.spring.auth.PrincipalAccess; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @@ -13,9 +15,10 @@ public ClientConfigController(ServiceDiscovery serviceDiscovery) { } @PostMapping("/client.config") - public ResponseEntity getConfig() { + public ResponseEntity getConfig(Authentication auth) { return ResponseEntity.ok(ClientConfigResponsePayload.builder() .components(serviceDiscovery.getComponents()) + .userProfile(PrincipalAccess.getUserProfile(auth)) .build()); } } diff --git a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java index 56f96a52b6..5ec8e9fd7f 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java @@ -1,5 +1,6 @@ package co.airy.core.api.config; +import co.airy.spring.auth.session.UserProfile; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -13,4 +14,5 @@ @AllArgsConstructor public class ClientConfigResponsePayload { private Map> components; + private UserProfile userProfile; } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java index 566b4347ad..d7c5fa06fc 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java @@ -28,6 +28,8 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; +import static co.airy.spring.auth.PrincipalAccess.getUserId; + @RestController public class SendMessageController { private final Stores stores; @@ -43,7 +45,7 @@ public class SendMessageController { } @PostMapping("/messages.send") - public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPayload payload) throws ExecutionException, InterruptedException, JsonProcessingException { + public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPayload payload, Authentication auth) throws ExecutionException, InterruptedException, JsonProcessingException { final ReadOnlyKeyValueStore conversationsStore = stores.getConversationsStore(); final Conversation conversation = conversationsStore.get(payload.getConversationId().toString()); @@ -56,6 +58,8 @@ public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPaylo return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } + final String userId = getUserId(auth); + final Message message = Message.newBuilder() .setId(UUID.randomUUID().toString()) .setChannelId(channel.getId()) @@ -64,8 +68,7 @@ public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPaylo .setHeaders(Map.of()) .setDeliveryState(DeliveryState.PENDING) .setSource(channel.getSource()) - // TODO add the oidc id here in https://github.com/airyhq/airy/issues/1518 - .setSenderId("airy-core-anonymous") + .setSenderId(userId) .setSentAt(Instant.now().toEpochMilli()) .setIsFromContact(false) .build(); diff --git a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java index a16dc58c56..11010016d7 100644 --- a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java +++ b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java @@ -1,42 +1,17 @@ package co.airy.core.api.websocket; -import co.airy.log.AiryLoggerFactory; -import org.slf4j.Logger; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.messaging.simp.stomp.StompCommand; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.web.server.ResponseStatusException; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; -import java.util.List; - @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - private static final Logger log = AiryLoggerFactory.getLogger(WebSocketConfig.class); - private final String systemToken; - private final String systemTokenPrincipal; - - public WebSocketConfig(@Value("${systemToken:#{null}}") String systemToken) { - this.systemToken = systemToken; - this.systemTokenPrincipal = systemToken == null ? null : String.format("system-token-%s", systemToken.substring(0, Math.min(systemToken.length(), 4))); - } - @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker() @@ -58,39 +33,4 @@ TaskScheduler heartbeatScheduler() { return heartbeatScheduler; } - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - registration.interceptors(new ChannelInterceptor() { - @Override - public Message preSend(Message message, MessageChannel channel) { - if (systemToken == null) { - return message; - } - - final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); - - if (accessor != null && StompCommand.CONNECT.equals(accessor.getCommand())) { - String authToken = accessor.getFirstNativeHeader(HttpHeaders.AUTHORIZATION); - if (authToken != null && authToken.startsWith("Bearer")) { - authToken = authToken.substring(7); - } - - try { - if (systemToken.equals(authToken)) { - accessor.setUser(new UsernamePasswordAuthenticationToken(systemTokenPrincipal, null, List.of())); - } - } catch (Exception e) { - log.error(String.format("STOMP Command: %s, token: %s \n Failed to authenticate", accessor.getCommand(), authToken)); - } - } - - if (accessor == null || accessor.getUser() == null) { - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); - } - - return message; - } - }); - } } diff --git a/cli/pkg/cmd/config/config.go b/cli/pkg/cmd/config/config.go index 2b18eb71f4..6b45bb65c5 100644 --- a/cli/pkg/cmd/config/config.go +++ b/cli/pkg/cmd/config/config.go @@ -37,9 +37,11 @@ func applyConfig(cmd *cobra.Command, args []string) { console.Exit("could not find an installation of Airy Core. Get started here https://airy.co/docs/core/getting-started/installation/introduction") } - if len(conf.Security) != 0 { - applyErr := kube.ApplyConfigMap("security", conf.Kubernetes.Namespace, conf.Security, map[string]string{}, clientset) + secData := conf.Security.getData() + if len(secData) != 0 { + applyErr := kube.ApplyConfigMap("security", conf.Kubernetes.Namespace, secData, map[string]string{}, clientset) if applyErr != nil { + // TODO should we error here? fmt.Printf("unable to apply configuration for \"security\"\n Error:\n %v\n", applyErr) } else { fmt.Printf("applied configuration for \"security\"\n") diff --git a/cli/pkg/cmd/config/parser.go b/cli/pkg/cmd/config/parser.go index bc58b70b34..bd80f92450 100644 --- a/cli/pkg/cmd/config/parser.go +++ b/cli/pkg/cmd/config/parser.go @@ -17,10 +17,39 @@ type componentsConf map[string]map[string]string type airyConf struct { Kubernetes kubernetesConf - Security map[string]string + Security securityConf Components map[string]componentsConf } +type securityConf struct { + SystemToken string `yaml:"systemToken"` + AllowedOrigins string `yaml:"allowedOrigins"` + JwtSecret string `yaml:"jwtSecret"` + Oidc map[string]string `yaml:"oidc"` +} + +func (s securityConf) getData() map[string]string { + m := make(map[string]string, len(s.Oidc)) + + if s.SystemToken != "" { + m["systemToken"] = s.SystemToken + } + if s.AllowedOrigins != "" { + m["allowedOrigins"] = s.AllowedOrigins + } + if s.JwtSecret != "" { + m["jwtSecret"] = s.JwtSecret + } + + for key, value := range s.Oidc { + if value != "" { + m["oidc." + key] = value + } + } + + return m +} + func parseConf(configFile string) (airyConf, error) { data, err := ioutil.ReadFile(configFile) if err != nil { diff --git a/cli/pkg/cmd/create/helm.go b/cli/pkg/cmd/create/helm.go index 1196e5a0b3..f3b8ff911f 100644 --- a/cli/pkg/cmd/create/helm.go +++ b/cli/pkg/cmd/create/helm.go @@ -151,16 +151,13 @@ func (h *Helm) runHelm(args []string) error { for event := range ch { switch event.Type { case watch.Error: - h.cleanupJob() return fmt.Errorf("helm run failed with error %v", event.Object) case watch.Added: case watch.Modified: job, _ := event.Object.(*batchv1.Job) if job.Status.Succeeded == 1 { - h.cleanupJob() return nil } else if job.Status.Failed == 1 { - h.cleanupJob() return fmt.Errorf("helm run failed with error %v", event.Object) } } diff --git a/cli/pkg/workspace/template/airy.yaml b/cli/pkg/workspace/template/airy.yaml index f2cbaf3fcf..67a9a0c061 100644 --- a/cli/pkg/workspace/template/airy.yaml +++ b/cli/pkg/workspace/template/airy.yaml @@ -2,3 +2,5 @@ kubernetes: containerRegistry: ghcr.io/airyhq namespace: default ngrokEnabled: false +security: + allowedOrigins: "*" diff --git a/docs/docs/api/authentication.md b/docs/docs/api/authentication.md index 77c017af20..4e3ef13245 100644 --- a/docs/docs/api/authentication.md +++ b/docs/docs/api/authentication.md @@ -3,7 +3,67 @@ title: Authentication sidebar_label: Authentication --- -By default, authentication is disabled. To protect your API endpoints you need to set the `security.systemToken` -[cluster configuration](getting-started/installation/configuration.md) value in your `airy.yaml` and apply it. +By default, authentication is disabled. There are two ways of protecting resources from unauthorized access. +You can set `security.systemToken` in the [cluster configuration](getting-started/installation/configuration.md) to a secure secret value in your `airy.yaml` and apply it. Once that is done you authenticate by setting the token as a value on the [Bearer Authorization header](https://tools.ietf.org/html/rfc6750#section-2.1) when making requests. -Once that is done you authenticate by setting the token as a value on the [Bearer Authorization header](https://tools.ietf.org/html/rfc6750#section-2.1) when making requests. +This is fine for API only access, but it means that UI clients will no longer work since api keys are not meant for web authentication. Therefore Airy Core also supports [Open Id Connect (OIDC)](https://openid.net/connect/) to allow your agents to authenticate via an external provider. If you configure this in addition to the system token then both types of authentication will work when requesting APIs. If you only configure OIDC authentication then regular + +## Configuring OIDC + +OIDC is an authentication layer on top of the popular OAuth 2.0 authorization framework. With the added information of +"who" made a request (authentication) Airy Core is able to offer audit and workflow features. + +### GitHub + +The easiest way to configure our OIDC is by using our GitHub preset. We will explain how to configure any OIDC provider further below. To get started you first need a GitHub OAuth app. You can follow [this guide](https://docs.github.com/en/developers/apps/creating-an-oauth-app) and as an Authorization Callback URL you need to put your Airy host with the +path `/login/oauth2/code/github`. So if your Airy Core instance is hosted at `https://airy.example.org` the Callback URL +would be `https://airy.example.org/login/oauth2/code/github` + +:::note + +You can always get your Airy host by running the CLI command `airy api endpoint` + +::: + +Now you can add your GitHub app configuration to the security section in your `airy.yaml`: + +```yaml +security: + oidc: + allowedEmailPatterns: "*@airy.co,grace@example.org" + provider: "github" + clientId: "github oauth client id" + clientSecret: "github oauth client secret" +``` + +Since you don't want just any GitHub user to be able to access your Airy Core instance you are also required to add +a list of emails or email wildcard patterns to define which users are authorized for use. + +Once this configuration is applied all new requests to the Airy Core API will be redirected to the Github +provider for login. If that login is successful the Airy Core platform will set a http only authentication cookie +that will authenticate the current user session. + +### Any open id provider + +To configure any open id connect provider for authentication we expose the following configuration values: + +```yaml +security: + oidc: + allowedEmailPatterns: "grace@example.org" + provider: "my-provider" + clientId: "client-id" + clientSecret: "client-secret" + scope: "openid,email" # comma separated list of scopes. Must include "openid" + clientAuthenticationMethod: "basic" # One of [basic,post,none] + authorizationGrantType: "authorization_code" # One of [authorization_code,implicit,refresh_token,client_credentials,password] + authorizationUri: "https://my-provider.org/oauth2/v1/authorize" + tokenUri: "https://my-provider.org/oauth2/v1/token" + userInfoUri: "https://my-provider.org/oauth2/v1/userinfo" + userInfoAuthenticationMethod: "form" # One of [header,form,query] + userNameAttributeName: "id" # Field name within the OIDC identity token that uniquely identifies the user + issuerUri: "https://my-provider.org/jwt-issuer" + jwkSetUri: "https://my-provider.org/oauth2/v1/certs" +``` + +The redirect Uri to configure with your provider will always be of the form `{airy core host}/login/oauth2/code/{provider name}`. diff --git a/docs/docs/getting-started/installation/configuration.md b/docs/docs/getting-started/installation/configuration.md index 591cf5976d..5de7bf1972 100644 --- a/docs/docs/getting-started/installation/configuration.md +++ b/docs/docs/getting-started/installation/configuration.md @@ -59,6 +59,8 @@ cluster and Redis. - `systemToken` set to a long secure secret to use for machine [API authentication](api/authentication.md) - `allowedOrigins` your site's origin to prevent CORS-based attacks (default: `"*"`) +- `oidc` a map of values that when set enable and define [OIDC authentication](api/authentication.md#configuring-oidc) +- `jwtSecret` used to create jwt http sessions derived from oidc authentication (default: randomized on installation) ### Components diff --git a/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml b/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml index b8e87081e0..59a13b746f 100644 --- a/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml @@ -7,4 +7,5 @@ data: {{- if .Values.systemToken }} systemToken: {{ .Values.systemToken | quote }} {{- end }} + jwtSecret: {{ .Values.jwtSecret | default (randAlphaNum 128) | quote }} allowedOrigins: {{ .Values.allowedOrigins | quote }} diff --git a/infrastructure/helm-chart/templates/ingress.yaml b/infrastructure/helm-chart/templates/ingress.yaml index 2624940c1f..6a14186ee3 100644 --- a/infrastructure/helm-chart/templates/ingress.yaml +++ b/infrastructure/helm-chart/templates/ingress.yaml @@ -92,6 +92,20 @@ spec: name: api-communication port: number: 80 + - path: /login + pathType: Prefix + backend: + service: + name: api-admin + port: + number: 80 + - path: /oauth + pathType: Prefix + backend: + service: + name: api-admin + port: + number: 80 - path: /client.config pathType: Prefix backend: @@ -99,6 +113,13 @@ spec: name: api-admin port: number: 80 + - path: /users.getProfile + pathType: Prefix + backend: + service: + name: api-admin + port: + number: 80 - path: /channels.list pathType: Prefix backend: diff --git a/lib/java/spring/auth/BUILD b/lib/java/spring/auth/BUILD index 6e8a788b93..64351172e6 100644 --- a/lib/java/spring/auth/BUILD +++ b/lib/java/spring/auth/BUILD @@ -11,6 +11,10 @@ lib_deps = [ "//lib/java/log", "//lib/java/spring/core:spring-core", "@maven//:javax_servlet_javax_servlet_api", + "@maven//:org_springframework_security_spring_security_core", + "@maven//:org_springframework_boot_spring_boot", + "@maven//:org_springframework_security_spring_security_oauth2_client", + "@maven//:org_springframework_boot_spring_boot_autoconfigure", "@maven//:javax_xml_bind_jaxb_api", ] @@ -20,13 +24,14 @@ custom_java_library( visibility = ["//visibility:public"], exports = [ "@maven//:org_springframework_security_spring_security_core", + "@maven//:org_springframework_security_spring_security_oauth2_core", ], deps = lib_deps, ) custom_java_library( name = "test-app", - srcs = ["src/test/java/co/airy/spring/auth/TestApp.java"], + srcs = glob(["src/test/java/co/airy/spring/auth/test_app/*.java"]), deps = lib_deps, ) diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java index 5616c07c1b..88704c2213 100644 --- a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java @@ -1,5 +1,14 @@ package co.airy.spring.auth; +import co.airy.log.AiryLoggerFactory; +import co.airy.spring.auth.oidc.ConfigProvider; +import co.airy.spring.auth.oidc.EmailFilter; +import co.airy.spring.auth.oidc.UserService; +import co.airy.spring.auth.session.AuthCookie; +import co.airy.spring.auth.session.CookieSecurityContextRepository; +import co.airy.spring.auth.session.Jwt; +import co.airy.spring.auth.token.AuthenticationFilter; +import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,6 +18,8 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -23,30 +34,59 @@ jsr250Enabled = true ) public class AuthConfig extends WebSecurityConfigurerAdapter { + private static final Logger log = AiryLoggerFactory.getLogger(AuthConfig.class); private final String[] ignoreAuthPatterns; private final String systemToken; + private final String jwtSecret; + private final UserService userService; + private final ConfigProvider configProvider; - public AuthConfig(@Value("${systemToken:#{null}}") String systemToken, List ignorePatternBeans) { + public AuthConfig(@Value("${systemToken:#{null}}") String systemToken, + @Value("${jwtSecret:#{null}}") String jwtSecret, + List ignorePatternBeans, + ConfigProvider configProvider, + UserService userService + ) { this.systemToken = systemToken; + this.jwtSecret = jwtSecret; this.ignoreAuthPatterns = ignorePatternBeans.stream() .flatMap((ignoreAuthPatternBean -> ignoreAuthPatternBean.getIgnorePattern().stream())) .toArray(String[]::new); + this.configProvider = configProvider; + this.userService = userService; } @Override protected void configure(final HttpSecurity http) throws Exception { http.cors().and() .csrf().disable() - // Don't let Spring create its own session - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); - if (this.systemToken != null) { - http.addFilter(new AuthenticationFilter(authenticationManager(), this.systemToken)) - .authorizeRequests(authorize -> authorize - .antMatchers("/actuator/**", "/ws*").permitAll() - .antMatchers(ignoreAuthPatterns).permitAll() - .anyRequest().authenticated() - ); + if (systemToken != null || configProvider.isPresent()) { + http.authorizeRequests(authorize -> authorize + .antMatchers("/actuator/**").permitAll() + .antMatchers(ignoreAuthPatterns).permitAll() + .anyRequest().authenticated() + ); + + if (systemToken != null) { + log.info("System token auth enabled"); + http.addFilterBefore(new AuthenticationFilter(systemToken), AnonymousAuthenticationFilter.class); + } + + if (configProvider.isPresent()) { + log.info("Oidc auth enabled with provider: {}", configProvider.getRegistration().getRegistrationId()); + http + .securityContext().securityContextRepository(new CookieSecurityContextRepository(new Jwt(jwtSecret))) + .and().logout().permitAll().deleteCookies(AuthCookie.NAME) + .and() + .oauth2Login(oauth2 -> oauth2 + .userInfoEndpoint(userInfo -> userInfo + .userService(this.userService) + )) + .addFilterAfter(new EmailFilter(configProvider), OAuth2LoginAuthenticationFilter.class); + } } } diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java new file mode 100644 index 0000000000..f9219fc1ca --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java @@ -0,0 +1,38 @@ +package co.airy.spring.auth; + +import co.airy.spring.auth.session.AiryAuth; +import co.airy.spring.auth.session.UserProfile; +import co.airy.spring.auth.token.TokenAuth; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; + +public class PrincipalAccess { + public static final String ANON_PRINCIPAL = "airy-core-anonymous"; + + public static String getUserId(Authentication authentication) { + if (authentication == null) { + return ANON_PRINCIPAL; + } + + if (authentication instanceof TokenAuth) { + return ((TokenAuth) authentication).getPrincipal(); + } + + final UserProfile userProfile = getUserProfile(authentication); + if (userProfile == null) { + throw new IllegalStateException("Unknown authentication type"); + } + + return userProfile.getId(); + } + + public static UserProfile getUserProfile(Authentication authentication) { + if (authentication instanceof OAuth2AuthenticationToken) { + return UserProfile.from((OAuth2AuthenticationToken) authentication); + } else if (authentication instanceof AiryAuth) { + return ((AiryAuth) authentication).getPrincipal(); + } + + return null; + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java new file mode 100644 index 0000000000..a46c2b4ec8 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java @@ -0,0 +1,41 @@ +package co.airy.spring.auth.oidc; + +import co.airy.spring.auth.oidc.github.GithubApi; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; + +@Configuration +public class ClientConfig { + @Bean + @ConditionalOnProperty({"oidc.provider", "oidc.allowedEmailPatterns"}) + public ClientRegistrationRepository clientRegistrationRepository(ConfigProvider config) { + return new InMemoryClientRegistrationRepository(config.getRegistration()); + } + + @Bean + @ConditionalOnBean(ClientRegistrationRepository.class) + public OAuth2AuthorizedClientService authorizedClientService( + ClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository); + } + + @Bean + @ConditionalOnBean(OAuth2AuthorizedClientService.class) + public OAuth2AuthorizedClientRepository authorizedClientRepository( + OAuth2AuthorizedClientService authorizedClientService) { + return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService); + } + + @Bean + public UserService userService(GithubApi githubApi) { + return new UserService(githubApi); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java new file mode 100644 index 0000000000..f7f1a77fff --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java @@ -0,0 +1,90 @@ +package co.airy.spring.auth.oidc; + +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; + +/** + * Customized presets adapted from + * org.springframework.security.config.oauth2.client.CommonOAuth2Provider + */ +public enum CommonProviders { + + GOOGLE { + @Override + public ClientRegistration.Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC, + DEFAULT_REDIRECT_URL); + builder.scope("openid", "profile", "email"); + builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth"); + builder.tokenUri("https://www.googleapis.com/oauth2/v4/token"); + builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs"); + builder.issuerUri("https://accounts.google.com"); + builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo"); + builder.userNameAttributeName(IdTokenClaimNames.SUB); + builder.clientName("Google"); + return builder; + } + + }, + + GITHUB { + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC, + DEFAULT_REDIRECT_URL); + builder.scope("read:user", "user:email"); + builder.authorizationUri("https://github.com/login/oauth/authorize"); + builder.tokenUri("https://github.com/login/oauth/access_token"); + builder.userInfoUri("https://api.github.com/user"); + builder.userNameAttributeName("id"); + builder.clientName("GitHub"); + return builder; + } + + }, + + FACEBOOK { + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.POST, + DEFAULT_REDIRECT_URL); + builder.scope("public_profile", "email"); + builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth"); + builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token"); + builder.userInfoUri("https://graph.facebook.com/me?fields=id,name,email"); + builder.userNameAttributeName("id"); + builder.clientName("Facebook"); + return builder; + } + + }, + + OKTA { + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC, + DEFAULT_REDIRECT_URL); + builder.scope("openid", "profile", "email"); + builder.userNameAttributeName(IdTokenClaimNames.SUB); + builder.clientName("Okta"); + return builder; + } + + }; + + private static final String DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}"; + + protected final ClientRegistration.Builder getBuilder(String registrationId, ClientAuthenticationMethod method, + String redirectUri) { + ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(registrationId); + builder.clientAuthenticationMethod(method); + builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE); + builder.redirectUri(redirectUri); + return builder; + } + + public abstract ClientRegistration.Builder getBuilder(String registrationId); +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java new file mode 100644 index 0000000000..19e242572c --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java @@ -0,0 +1,83 @@ +package co.airy.spring.auth.oidc; + +import lombok.Getter; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Component +public class ConfigProvider { + @Getter + private ClientRegistration registration; + private List> emailMatchers; + + public ConfigProvider(UserProperties props) { + if (props.getProvider() == null || props.getAllowedEmailPatterns() == null) { + return; + } + + ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(props.getProvider()); + try { + final CommonProviders commonProvider = CommonProviders.valueOf(props.getProvider().toUpperCase()); + builder = commonProvider.getBuilder(props.getProvider()); + } catch (Exception expected) { + // not a common oauth provider + } + + builder.clientId(props.getClientId()).clientSecret(props.getClientSecret()); + + if (props.getClientAuthenticationMethod() != null) { + builder.clientAuthenticationMethod(props.getClientAuthenticationMethod()); + } + if (props.getAuthorizationGrantType() != null) { + builder.authorizationGrantType(props.getAuthorizationGrantType()); + } + if (props.getAuthorizationUri() != null) { + builder.authorizationUri(props.getAuthorizationUri()); + } + if (props.getTokenUri() != null) { + builder.tokenUri(props.getTokenUri()); + } + if (props.getUserInfoUri() != null) { + builder.userInfoUri(props.getUserInfoUri()); + } + if (props.getUserInfoAuthenticationMethod() != null) { + builder.userInfoAuthenticationMethod(props.getUserInfoAuthenticationMethod()); + } + if (props.getUserNameAttributeName() != null) { + builder.userNameAttributeName(props.getUserNameAttributeName()); + } + if (props.getIssuerUri() != null) { + builder.issuerUri(props.getIssuerUri()); + } + if (props.getJwkSetUri() != null) { + builder.jwkSetUri(props.getJwkSetUri()); + } + if (props.getScope() != null) { + builder.scope(props.getScope()); + } + + registration = builder.build(); + + emailMatchers = Arrays.stream(props.getAllowedEmailPatterns().split(",")) + .map(this::regexFromWildcard).map(Pattern::asMatchPredicate).collect(Collectors.toList()); + } + + private Pattern regexFromWildcard(String pattern) { + final String s = pattern.replaceAll("\\*", ".*"); + return Pattern.compile(s); + } + + public boolean isPresent() { + return emailMatchers != null && registration != null; + } + + public boolean emailMatches(String email) { + return emailMatchers.stream().anyMatch((matches) -> matches.test(email)); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java new file mode 100644 index 0000000000..8fbd609670 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java @@ -0,0 +1,58 @@ +package co.airy.spring.auth.oidc; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class EmailFilter extends OncePerRequestFilter { + private final ConfigProvider configProvider; + + public EmailFilter(ConfigProvider config) { + this.configProvider = config; + } + + @Override + protected void doFilterInternal(HttpServletRequest req, + HttpServletResponse res, + FilterChain chain) throws IOException, ServletException { + final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth instanceof OAuth2AuthenticationToken) { + final OAuth2User user = ((OAuth2AuthenticationToken) auth).getPrincipal(); + final List emails = getEmails(user); + + + if (emails.stream().noneMatch(configProvider::emailMatches)) { + res.sendError(403, "Email not allowed"); + return; + } + } + + chain.doFilter(req, res); + } + + private List getEmails(OAuth2User user) { + final ArrayList emails = new ArrayList<>(); + + final Map attrs = user.getAttributes(); + Optional.ofNullable(attrs.get("email")) + .ifPresent((email) -> emails.add((String) email)); + + Optional.ofNullable(attrs.get("emails")) + .ifPresent((allEmails) -> emails.addAll((Collection) allEmails)); + + return emails; + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java new file mode 100644 index 0000000000..9bf231728a --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java @@ -0,0 +1,58 @@ +package co.airy.spring.auth.oidc; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.security.oauth2.core.AuthenticationMethod; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +@Data +@Component +@ConfigurationProperties(prefix = "oidc") +public class UserProperties { + private String allowedEmailPatterns; + private String provider; + private String clientId; + private String clientSecret; + + // Config values for manual provider configuration + private String clientAuthenticationMethod; + public ClientAuthenticationMethod getClientAuthenticationMethod() { + return Optional.ofNullable(clientAuthenticationMethod).map(ClientAuthenticationMethod::new).orElse(null); + } + + private String authorizationGrantType; + public AuthorizationGrantType getAuthorizationGrantType() { + return Optional.ofNullable(authorizationGrantType).map(AuthorizationGrantType::new).orElse(null); + } + + private String authorizationUri; + private String tokenUri; + private String userInfoUri; + + private String userInfoAuthenticationMethod; + public AuthenticationMethod getUserInfoAuthenticationMethod() { + return Optional.ofNullable(userInfoAuthenticationMethod).map(AuthenticationMethod::new).orElse(null); + } + + private String userNameAttributeName; + private String issuerUri; + private String jwkSetUri; + + private String scope; + + public Collection getScope() { + if (scope == null) { + return null; + } + + return Arrays.asList(scope.split(",")); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java new file mode 100644 index 0000000000..102dac84fa --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java @@ -0,0 +1,52 @@ +package co.airy.spring.auth.oidc; + +import co.airy.spring.auth.oidc.github.EmailsResponse; +import co.airy.spring.auth.oidc.github.GithubApi; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.toList; + +public class UserService implements OAuth2UserService { + private final GithubApi githubApi; + private final DefaultOAuth2UserService userService = new DefaultOAuth2UserService(); + + public UserService(GithubApi githubApi) { + this.githubApi = githubApi; + } + + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + OAuth2User user = userService.loadUser(userRequest); + + // Github does not return a user's email by default + if ("github".equals(userRequest.getClientRegistration().getRegistrationId())) { + user = addGithubEmails(user, userRequest); + } + + return user; + } + + private OAuth2User addGithubEmails(OAuth2User user, OAuth2UserRequest userRequest) { + try { + final List userEmails = this.githubApi.getUserEmails(userRequest.getAccessToken().getTokenValue()); + + final Map attributes = new HashMap<>(user.getAttributes()); + attributes.put("emails", userEmails.stream().map(EmailsResponse::getEmail).collect(toList())); + + return new DefaultOAuth2User(user.getAuthorities(), attributes, userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint() + .getUserNameAttributeName()); + } catch (Exception e) { + throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INSUFFICIENT_SCOPE), e.getMessage()); + } + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java new file mode 100644 index 0000000000..be96b4ce50 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java @@ -0,0 +1,10 @@ +package co.airy.spring.auth.oidc.github; + +import lombok.Data; + +@Data +public class EmailsResponse { + private String email; + private Boolean primary; + private Boolean verified; +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java new file mode 100644 index 0000000000..4dc2d036d6 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java @@ -0,0 +1,49 @@ +package co.airy.spring.auth.oidc.github; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.ApplicationListener; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +@Component +public class GithubApi implements ApplicationListener { + private RestTemplate restTemplate; + private final RestTemplateBuilder restTemplateBuilder; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final URI githubEmailUri = URI.create("https://api.github.com/user/emails"); + + public GithubApi(RestTemplateBuilder restTemplateBuilder) { + this.restTemplateBuilder = restTemplateBuilder; + } + + public List getUserEmails(String accessToken) { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setBearerAuth(accessToken); + + RequestEntity> request = new RequestEntity<>(headers, HttpMethod.GET, githubEmailUri); + ResponseEntity> response = restTemplate.exchange(request, new ParameterizedTypeReference>() { + }); + return response.getBody(); + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + restTemplate = restTemplateBuilder + .additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper)) + .build(); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java new file mode 100644 index 0000000000..39d0138b24 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java @@ -0,0 +1,53 @@ +package co.airy.spring.auth.session; + +import lombok.NoArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; + +import java.io.Serializable; +import java.util.Collection; + +@NoArgsConstructor +public class AiryAuth implements Authentication, Serializable { + private UserProfile userProfile; + private boolean isAuthenticated = true; + + public AiryAuth(UserProfile userProfile) { + this.userProfile = userProfile; + } + + @Override + public Collection getAuthorities() { + return null; + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getDetails() { + return null; + } + + @Override + public UserProfile getPrincipal() { + return userProfile; + } + + @Override + public boolean isAuthenticated() { + return this.isAuthenticated; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + this.isAuthenticated = true; + } + + @Override + public String getName() { + return userProfile.getId(); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java new file mode 100644 index 0000000000..197cfc59cf --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java @@ -0,0 +1,14 @@ +package co.airy.spring.auth.session; + +import javax.servlet.http.Cookie; + +public class AuthCookie extends Cookie { + public static String NAME = "airy_auth_token"; + private static final String PATH = "/"; + + public AuthCookie(String value) { + super(NAME, value); + this.setPath(PATH); + this.setHttpOnly(true); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java new file mode 100644 index 0000000000..3a49068457 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java @@ -0,0 +1,117 @@ +package co.airy.spring.auth.session; + +import co.airy.log.AiryLoggerFactory; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.slf4j.Logger; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.web.context.HttpRequestResponseHolder; +import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper; +import org.springframework.security.web.context.SecurityContextRepository; +import org.springframework.web.util.WebUtils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Optional; +import java.util.stream.Stream; + +import static co.airy.spring.auth.PrincipalAccess.getUserProfile; + +/** + * Spring's default session store attaches a session id and stores the security context in memory. + *

+ * We prefer to store the authentication state on the client, which allows us to authenticate users + * against any Spring app without the need for them to maintain another datastore. + */ +public class CookieSecurityContextRepository implements SecurityContextRepository { + private static final Logger log = AiryLoggerFactory.getLogger(CookieSecurityContextRepository.class); + private final Jwt jwt; + + public CookieSecurityContextRepository(Jwt jwt) { + this.jwt = jwt; + } + + @Override + public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { + HttpServletRequest request = requestResponseHolder.getRequest(); + HttpServletResponse response = requestResponseHolder.getResponse(); + requestResponseHolder.setResponse(new SaveToCookieResponseWrapper(request, response)); + + SecurityContext context = SecurityContextHolder.createEmptyContext(); + getStoredAuth(request) + .ifPresent(context::setAuthentication); + + return context; + } + + @Override + public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) { + SaveToCookieResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, + SaveToCookieResponseWrapper.class); + if (responseWrapper != null && !responseWrapper.isContextSaved()) { + responseWrapper.saveContext(context); + } + } + + @Override + public boolean containsContext(HttpServletRequest request) { + return getStoredAuth(request).isPresent(); + } + + private Optional getStoredAuth(HttpServletRequest request) { + return getCookie(request) + .map((authCookie) -> { + try { + return jwt.loadFromToken(authCookie.getValue()); + } catch (Exception e) { + log.warn("Clearing user session because token could not be decoded", e); + return null; + } + }); + } + + private Optional getCookie(HttpServletRequest request) { + if (request.getCookies() == null) { + return Optional.empty(); + } + + return Stream.of(request.getCookies()) + .filter(c -> AuthCookie.NAME.equals(c.getName()) && !c.getValue().equals("")) + .findFirst(); + } + + private class SaveToCookieResponseWrapper extends SaveContextOnUpdateOrErrorResponseWrapper { + private final HttpServletRequest request; + + SaveToCookieResponseWrapper(HttpServletRequest request, HttpServletResponse response) { + super(response, true); + this.request = request; + } + + @Override + protected void saveContext(SecurityContext securityContext) { + HttpServletResponse response = (HttpServletResponse) getResponse(); + Authentication authentication = securityContext.getAuthentication(); + + if (authentication instanceof OAuth2AuthenticationToken) { + try { + // Exchange the oauth2 session for an Airy JWT cookie session + final UserProfile profile = getUserProfile(authentication); + final AiryAuth airyAuth = new AiryAuth(profile); + + AuthCookie cookie = new AuthCookie(jwt.getAuthToken(airyAuth)); + cookie.setSecure(request.isSecure()); + response.addCookie(cookie); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } else if (authentication == null || !authentication.isAuthenticated()) { + // Remove the cookie if there is no auth present + response.addCookie(new AuthCookie("")); + } + } + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java new file mode 100644 index 0000000000..039851d40b --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java @@ -0,0 +1,65 @@ +package co.airy.spring.auth.session; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; +import java.security.Key; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class Jwt { + public static final String PRINCIPAL_CLAIM = "principal"; + private final ObjectMapper objectMapper; + private final Key signingKey; + + public Jwt(String tokenKey) { + this.signingKey = parseSigningKey(tokenKey); + this.objectMapper = new ObjectMapper(); + } + + public String getAuthToken(AiryAuth auth) throws JsonProcessingException { + Date now = Date.from(Instant.now()); + + Map claims = new HashMap<>(); + claims.put(PRINCIPAL_CLAIM, objectMapper.writeValueAsString(auth.getPrincipal())); + + JwtBuilder builder = Jwts.builder() + .setId(UUID.randomUUID().toString()) + .setSubject(auth.getPrincipal().getName()) + .setIssuedAt(now) + .addClaims(claims) + .signWith(signingKey, SignatureAlgorithm.HS256); + + Date exp = Date.from(Instant.now().plus(Duration.ofDays(30))); + builder.setExpiration(exp); + + return builder.compact(); + } + + public AiryAuth loadFromToken(final String authHeader) throws Exception { + Claims claims = extractClaims(authHeader); + final String principalClaim = (String) claims.get(PRINCIPAL_CLAIM); + final UserProfile profile = objectMapper.readValue(principalClaim, UserProfile.class); + return new AiryAuth(profile); + } + + + private Key parseSigningKey(String tokenKey) { + byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(tokenKey); + return new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName()); + } + + private Claims extractClaims(String token) { + return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token).getBody(); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java new file mode 100644 index 0000000000..f7643ce50a --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java @@ -0,0 +1,34 @@ +package co.airy.spring.auth.session; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.AuthenticatedPrincipal; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.oidc.OidcUserInfo; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.oauth2.core.user.OAuth2User; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserProfile implements AuthenticatedPrincipal { + private String id; + private String name; + private String avatarUrl; + + public static UserProfile from(OAuth2AuthenticationToken auth) { + final OAuth2User user = auth.getPrincipal(); + + // e.g. github:4403838 + if (user instanceof OidcUser) { + final String id = String.format("%s:%s", auth.getAuthorizedClientRegistrationId(), + user.getName()); + return new UserProfile(id, ((OidcUser) user).getFullName(), ((OidcUser) user).getPicture()); + } + + final String id = String.format("%s:%s", auth.getAuthorizedClientRegistrationId(), + user.getAttribute("id")); + return new UserProfile(id, user.getAttribute("name"), user.getAttribute("avatar_url")); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthenticationFilter.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/AuthenticationFilter.java similarity index 54% rename from lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthenticationFilter.java rename to lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/AuthenticationFilter.java index 4c024c6652..9608de905e 100644 --- a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthenticationFilter.java +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/AuthenticationFilter.java @@ -1,26 +1,20 @@ -package co.airy.spring.auth; +package co.airy.spring.auth.token; import org.springframework.http.HttpHeaders; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.List; -public class AuthenticationFilter extends BasicAuthenticationFilter { +public class AuthenticationFilter extends OncePerRequestFilter { private final String systemToken; - private final String systemTokenPrincipal; - public AuthenticationFilter(AuthenticationManager authManager, String systemToken) { - super(authManager); + public AuthenticationFilter(String systemToken) { this.systemToken = systemToken; - this.systemTokenPrincipal = systemToken == null ? null : String.format("system-token-%s", systemToken.substring(0, Math.min(systemToken.length(), 4))); } @Override @@ -37,19 +31,20 @@ protected void doFilterInternal(HttpServletRequest req, return; } - UsernamePasswordAuthenticationToken authentication = getAuthentication(authToken); + TokenAuth authentication = getAuthentication(authToken); if (authentication == null) { - res.sendError(HttpServletResponse.SC_FORBIDDEN); + res.sendError(403, "system token does not match"); return; } + authentication.setAuthenticated(true); SecurityContextHolder.getContext().setAuthentication(authentication); chain.doFilter(req, res); } - private UsernamePasswordAuthenticationToken getAuthentication(String token) { + private TokenAuth getAuthentication(String token) { if (systemToken != null && systemToken.equals(token)) { - return new UsernamePasswordAuthenticationToken(systemTokenPrincipal, null, List.of()); + return new TokenAuth(token); } return null; diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java new file mode 100644 index 0000000000..3c4a8b3181 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java @@ -0,0 +1,50 @@ +package co.airy.spring.auth.token; + +import lombok.Data; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; + +import java.util.Collection; +import java.util.List; + +@Data +public class TokenAuth implements Authentication { + private String token; + private String principal; + private boolean isAuthenticated = false; + + public TokenAuth(String token) { + this.principal = String.format("system-token-%s", token.substring(0, Math.min(token.length(), 4))); + } + + @Override + public Collection getAuthorities() { + return List.of(); + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getDetails() { + return null; + } + + @Override + public boolean isAuthenticated() { + return this.isAuthenticated; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + this.isAuthenticated = true; + } + + + @Override + public String getName() { + return principal; + } +} diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/JwtAuthenticationFilterTest.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/AuthenticationTest.java similarity index 87% rename from lib/java/spring/auth/src/test/java/co/airy/spring/auth/JwtAuthenticationFilterTest.java rename to lib/java/spring/auth/src/test/java/co/airy/spring/auth/AuthenticationTest.java index 2809e4f62c..50400616c0 100644 --- a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/JwtAuthenticationFilterTest.java +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/AuthenticationTest.java @@ -20,11 +20,10 @@ @SpringBootTest(properties = { "allowedOrigins=*", "systemToken=user-generated-api-token", - "allowedOrigins=*" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AirySpringBootApplication.class) @AutoConfigureMockMvc @ExtendWith(SpringExtension.class) -public class JwtAuthenticationFilterTest { +public class AuthenticationTest { @Autowired private MockMvc mvc; @@ -47,15 +46,6 @@ void setsCorsHeaders() throws Exception { .andExpect(header().string("Access-Control-Allow-Origin", origin)); } - @Test - void rejectsInvalidJwt() throws Exception { - mvc.perform(post("/principal.get") - .header(HttpHeaders.AUTHORIZATION, "not a jwt") - ) - .andExpect(status().isForbidden()) - .andExpect(jsonPath("$").doesNotExist()); - } - @Test void authenticatesSystemToken() throws Exception { mvc.perform(post("/principal.get") diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java new file mode 100644 index 0000000000..e7d24d4bf2 --- /dev/null +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java @@ -0,0 +1,30 @@ +package co.airy.spring.auth; + +import co.airy.spring.core.AirySpringBootApplication; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(properties = { + "allowedOrigins=*", +}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AirySpringBootApplication.class) +@AutoConfigureMockMvc +@ExtendWith(SpringExtension.class) +public class NoAuthTest { + + @Autowired + private MockMvc mvc; + + @Test + void shouldNotAuthorize() throws Exception { + mvc.perform(post("/data.get")) + .andExpect(status().isOk()); + } +} diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java new file mode 100644 index 0000000000..6da7caea98 --- /dev/null +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java @@ -0,0 +1,49 @@ +package co.airy.spring.auth; + +import co.airy.spring.core.AirySpringBootApplication; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(properties = { + "systemToken=user-generated-api-token", + "jwtSecret=long-randomly-generated-secret-used-as-jwt-secret-key", + "oidc.provider=github", + "oidc.allowedEmailPatterns=grace@example.com", + "oidc.clientId=oauth-registration-id", + "oidc.clientSecret=oauth-secret" +}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AirySpringBootApplication.class) +@AutoConfigureMockMvc +@ExtendWith(SpringExtension.class) +public class OidcTest { + + @Autowired + private MockMvc mvc; + + @Test + void redirectsToAuth() throws Exception { + mvc.perform(post("/principal.get")) + .andExpect(status().is3xxRedirection()) + .andExpect(header().exists("Location")) + .andExpect(jsonPath("$").doesNotExist()); + } + + @Test + void systemTokenAuthStillWorks() throws Exception { + mvc.perform(post("/principal.get") + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .header(HttpHeaders.AUTHORIZATION, "user-generated-api-token")) + .andExpect(status().isOk()); + } +} diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/TestApp.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/test_app/Controller.java similarity index 79% rename from lib/java/spring/auth/src/test/java/co/airy/spring/auth/TestApp.java rename to lib/java/spring/auth/src/test/java/co/airy/spring/auth/test_app/Controller.java index 4f439aca03..39770072a1 100644 --- a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/TestApp.java +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/test_app/Controller.java @@ -1,4 +1,4 @@ -package co.airy.spring.auth; +package co.airy.spring.auth.test_app; import lombok.AllArgsConstructor; import lombok.Data; @@ -9,13 +9,19 @@ import org.springframework.web.bind.annotation.RestController; @RestController -public class TestApp { +public class Controller { @PostMapping("/principal.get") ResponseEntity echoPrincipal(Authentication authentication) { final String userId = (String) authentication.getPrincipal(); return ResponseEntity.ok(new PrincipalDetails(userId)); } + + + @PostMapping("/data.get") + ResponseEntity getData() { + return ResponseEntity.ok().build(); + } } @Data diff --git a/maven_install.json b/maven_install.json index 6bac8d9d74..5b465d261c 100644 --- a/maven_install.json +++ b/maven_install.json @@ -1,6 +1,6 @@ { "dependency_tree": { - "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 401678455, + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": -1641397329, "conflict_resolution": { "com.fasterxml.jackson.core:jackson-annotations:2.10.0": "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "com.fasterxml.jackson.core:jackson-core:2.10.0": "com.fasterxml.jackson.core:jackson-core:2.11.4", @@ -70,7 +70,7 @@ "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "software.amazon.ion:ion-java:1.0.2", - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.fasterxml.jackson.core:jackson-databind:jar:2.11.4", "joda-time:joda-time:2.10.2", @@ -109,7 +109,7 @@ "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "software.amazon.ion:ion-java:1.0.2", - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "com.fasterxml.jackson.core:jackson-databind:2.11.4", "org.apache.httpcomponents:httpcore:4.4.13", "com.fasterxml.jackson.core:jackson-databind:jar:2.11.4", @@ -146,7 +146,7 @@ "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "software.amazon.ion:ion-java:1.0.2", - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "com.fasterxml.jackson.core:jackson-databind:2.11.4", "org.apache.httpcomponents:httpcore:4.4.13", "com.fasterxml.jackson.core:jackson-databind:jar:2.11.4", @@ -792,6 +792,25 @@ "sha256": "973431c14b4d09a86e23b7184116fcac2d85501eb4a7430f7d185cce1af46050", "url": "https://repo1.maven.org/maven2/com/github/luben/zstd-jni/1.4.5-2/zstd-jni-1.4.5-2.jar" }, + { + "coord": "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar", + "https://repo1.maven.org/maven2/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar", + "https://jitpack.io/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar" + ], + "sha256": "4fccff8382aafc589962c4edb262f6aa595e34f1e11e61057d1c6a96e8fc7323", + "url": "https://repo1.maven.org/maven2/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar" + }, { "coord": "com.google.auth:google-auth-library-credentials:0.20.0", "dependencies": [], @@ -822,9 +841,9 @@ "com.google.code.findbugs:jsr305:3.0.2", "com.google.auto.value:auto-value-annotations:1.7", "com.google.auth:google-auth-library-credentials:0.20.0", - "commons-codec:commons-codec:1.11", "io.opencensus:opencensus-api:0.24.0", "io.grpc:grpc-context:1.22.1", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.google.http-client:google-http-client-jackson2:1.34.0", "com.google.errorprone:error_prone_annotations:2.3.4", @@ -1013,9 +1032,9 @@ "io.opencensus:opencensus-contrib-http-util:0.24.0", "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.google.code.findbugs:jsr305:3.0.2", - "commons-codec:commons-codec:1.11", "io.opencensus:opencensus-api:0.24.0", "io.grpc:grpc-context:1.22.1", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.google.errorprone:error_prone_annotations:2.3.4", "com.google.http-client:google-http-client:1.34.0", @@ -1051,9 +1070,9 @@ "commons-logging:commons-logging:1.2", "io.opencensus:opencensus-contrib-http-util:0.24.0", "com.google.code.findbugs:jsr305:3.0.2", - "commons-codec:commons-codec:1.11", "io.opencensus:opencensus-api:0.24.0", "io.grpc:grpc-context:1.22.1", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.google.errorprone:error_prone_annotations:2.3.4", "com.google.guava:failureaccess:1.0.1", @@ -1247,6 +1266,107 @@ "sha256": "2f8dca7b5487d6adda3b47e5584e074eae37a7d85e8aaeb5516ed8d390101d36", "url": "https://repo1.maven.org/maven2/com/kjetland/mbknor-jackson-jsonschema_2.12/1.0.39/mbknor-jackson-jsonschema_2.12-1.0.39.jar" }, + { + "coord": "com.nimbusds:content-type:2.1", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/content-type/2.1/content-type-2.1.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/content-type/2.1/content-type-2.1.jar", + "https://repo1.maven.org/maven2/com/nimbusds/content-type/2.1/content-type-2.1.jar", + "https://jitpack.io/com/nimbusds/content-type/2.1/content-type-2.1.jar" + ], + "sha256": "f37ae072a89350d42d9508def6a40255f2671e6303da1bb0905d35b83ca48555", + "url": "https://repo1.maven.org/maven2/com/nimbusds/content-type/2.1/content-type-2.1.jar" + }, + { + "coord": "com.nimbusds:lang-tag:1.4.4", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar", + "https://repo1.maven.org/maven2/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar", + "https://jitpack.io/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar" + ], + "sha256": "e49d2c694bb80c7036c177f2aabf53b7156061a68bd19dfd60e2bd370709e0c5", + "url": "https://repo1.maven.org/maven2/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar" + }, + { + "coord": "com.nimbusds:nimbus-jose-jwt:8.21", + "dependencies": [ + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "net.minidev:json-smart:2.3", + "org.ow2.asm:asm:9.0", + "net.minidev:accessors-smart:1.2" + ], + "directDependencies": [ + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "net.minidev:json-smart:2.3" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar", + "https://repo1.maven.org/maven2/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar", + "https://jitpack.io/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar" + ], + "sha256": "c6225341ea4b2659fb3862dff88c6b1f2fbb7f599ddfe48590bd31d142558dc2", + "url": "https://repo1.maven.org/maven2/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar" + }, + { + "coord": "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.ow2.asm:asm:9.0", + "com.nimbusds:lang-tag:1.4.4", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "com.nimbusds:content-type:2.1", + "net.minidev:json-smart:2.3" + ], + "directDependencies": [ + "com.nimbusds:lang-tag:1.4.4", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "com.nimbusds:content-type:2.1", + "net.minidev:json-smart:2.3" + ], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar", + "https://repo1.maven.org/maven2/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar", + "https://jitpack.io/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar" + ], + "sha256": "e89aaae9300fde54bc36eecb5f78a9a2878552d9ed2cc8781e61b7506588d50a", + "url": "https://repo1.maven.org/maven2/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar" + }, { "coord": "com.puppycrawl.tools:checkstyle:8.37", "dependencies": [ @@ -1404,6 +1524,29 @@ "sha256": "d84d4ba8b55cdb7fdcbb885e6939386367433f56f5ab8cfdc302a7c3587fa92b", "url": "https://repo1.maven.org/maven2/com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1.jar" }, + { + "coord": "com.sun.mail:jakarta.mail:1.6.7", + "dependencies": [ + "com.sun.activation:jakarta.activation:1.2.1" + ], + "directDependencies": [ + "com.sun.activation:jakarta.activation:1.2.1" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar", + "https://repo1.maven.org/maven2/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar", + "https://jitpack.io/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar" + ], + "sha256": "1b258ef45fae93059b65d0a0dd109e59ab93e8cd8a735ff66b2ba85f870d5150", + "url": "https://repo1.maven.org/maven2/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar" + }, { "coord": "com.thoughtworks.paranamer:paranamer:2.8", "dependencies": [], @@ -1606,7 +1749,7 @@ "url": "https://repo1.maven.org/maven2/commons-cli/commons-cli/1.4/commons-cli-1.4.jar" }, { - "coord": "commons-codec:commons-codec:1.11", + "coord": "commons-codec:commons-codec:1.14", "dependencies": [], "directDependencies": [], "exclusions": [ @@ -1615,14 +1758,14 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/commons-codec/commons-codec/1.11/commons-codec-1.11.jar", + "file": "v1/https/repo1.maven.org/maven2/commons-codec/commons-codec/1.14/commons-codec-1.14.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/commons-codec/commons-codec/1.11/commons-codec-1.11.jar", - "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.11/commons-codec-1.11.jar", - "https://jitpack.io/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" + "https://packages.confluent.io/maven/commons-codec/commons-codec/1.14/commons-codec-1.14.jar", + "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.14/commons-codec-1.14.jar", + "https://jitpack.io/commons-codec/commons-codec/1.14/commons-codec-1.14.jar" ], - "sha256": "e599d5318e97aa48f42136a2927e6dfa4e8881dff0e6c8e3109ddbbff51d7b7d", - "url": "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" + "sha256": "a128e4f93fabe5381ded64cf2873019e06030b718eb43ceeae0b0e5d17ad33e9", + "url": "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.14/commons-codec-1.14.jar" }, { "coord": "commons-collections:commons-collections:3.2.2", @@ -4066,11 +4209,11 @@ "coord": "org.apache.httpcomponents:httpclient:4.5.13", "dependencies": [ "org.apache.httpcomponents:httpcore:4.4.13", - "commons-logging:commons-logging:1.2", - "commons-codec:commons-codec:1.11" + "commons-codec:commons-codec:1.14", + "commons-logging:commons-logging:1.2" ], "directDependencies": [ - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "commons-logging:commons-logging:1.2", "org.apache.httpcomponents:httpcore:4.4.13" ], @@ -7321,6 +7464,61 @@ "sha256": "19d3249ade85335c80b32570a26c2367046d488b6d84b4e1172a3ed5d6d52279", "url": "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-json/2.4.5/spring-boot-starter-json-2.4.5.jar" }, + { + "coord": "org.springframework.boot:spring-boot-starter-oauth2-client:2.4.5", + "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.springframework.security:spring-security-oauth2-jose:5.4.6", + "org.springframework.boot:spring-boot-autoconfigure:2.4.5", + "org.ow2.asm:asm:9.0", + "org.springframework.security:spring-security-web:5.4.6", + "com.nimbusds:lang-tag:1.4.4", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "org.springframework:spring-context:5.3.6", + "com.sun.mail:jakarta.mail:1.6.7", + "org.springframework.security:spring-security-config:5.4.6", + "org.springframework.security:spring-security-oauth2-client:5.4.6", + "org.springframework:spring-expression:5.3.6", + "jakarta.annotation:jakarta.annotation-api:1.3.5", + "org.springframework:spring-web:5.3.6", + "com.nimbusds:content-type:2.1", + "com.sun.activation:jakarta.activation:1.2.1", + "org.springframework:spring-core:5.3.6", + "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6", + "org.springframework.boot:spring-boot:2.4.5", + "org.yaml:snakeyaml:1.27", + "net.minidev:json-smart:2.3", + "org.springframework.boot:spring-boot-starter:2.4.5" + ], + "directDependencies": [ + "org.springframework.security:spring-security-oauth2-jose:5.4.6", + "com.sun.mail:jakarta.mail:1.6.7", + "org.springframework.security:spring-security-config:5.4.6", + "org.springframework.security:spring-security-oauth2-client:5.4.6", + "org.springframework.security:spring-security-core:5.4.6", + "org.springframework.boot:spring-boot-starter:2.4.5" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar", + "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar", + "https://jitpack.io/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar" + ], + "sha256": "79298ed9006a065879f15e9a69dba147e6d6a0e0ab452e63bd38920a3de05bc1", + "url": "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar" + }, { "coord": "org.springframework.boot:spring-boot-starter-security:2.4.5", "dependencies": [ @@ -7678,6 +7876,47 @@ "sha256": "71e7cb0d33e3f595011d3e98b14f41ca165a435760ecd4d68cb935e8afa8a3d2", "url": "https://repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar" }, + { + "coord": "org.springframework.security.oauth:spring-security-oauth2:2.4.1.RELEASE", + "dependencies": [ + "org.springframework.security:spring-security-web:5.4.6", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-webmvc:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "org.springframework:spring-context:5.3.6", + "org.springframework.security:spring-security-config:5.4.6", + "commons-codec:commons-codec:1.14", + "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", + "org.springframework:spring-core:5.3.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" + ], + "directDependencies": [ + "org.springframework.security:spring-security-web:5.4.6", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-webmvc:5.3.6", + "org.springframework:spring-context:5.3.6", + "org.springframework.security:spring-security-config:5.4.6", + "commons-codec:commons-codec:1.14", + "org.springframework:spring-core:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar", + "https://repo1.maven.org/maven2/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar", + "https://jitpack.io/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar" + ], + "sha256": "333d00f579f244a047a0f997850a23488632037bc7d30fb760a73ed6a6f8f588", + "url": "https://repo1.maven.org/maven2/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar" + }, { "coord": "org.springframework.security:spring-security-config:5.4.6", "dependencies": [ @@ -7743,6 +7982,122 @@ "sha256": "dc75ecb94dad7625a0e1af31e8bc22ee9c119433c901aaf9b0d9454d6f6df783", "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar" }, + { + "coord": "org.springframework.security:spring-security-oauth2-client:5.4.6", + "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.ow2.asm:asm:9.0", + "org.springframework.security:spring-security-web:5.4.6", + "com.nimbusds:lang-tag:1.4.4", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "org.springframework:spring-context:5.3.6", + "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", + "com.nimbusds:content-type:2.1", + "org.springframework:spring-core:5.3.6", + "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6", + "net.minidev:json-smart:2.3" + ], + "directDependencies": [ + "org.springframework.security:spring-security-web:5.4.6", + "org.springframework:spring-core:5.3.6", + "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework.security:spring-security-core:5.4.6" + ], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar" + ], + "sha256": "db27a98c2c1b602d5d9e63387ba2b4b7a45e13cdd13120803256c5abde77e358", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar" + }, + { + "coord": "org.springframework.security:spring-security-oauth2-core:5.4.6", + "dependencies": [ + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "org.springframework:spring-context:5.3.6", + "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", + "org.springframework:spring-core:5.3.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" + ], + "directDependencies": [ + "org.springframework:spring-core:5.3.6", + "org.springframework:spring-web:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar" + ], + "sha256": "e13af768309b30b357bb78ae40a2bcbc40565916357e6156c3e94669ed7b7f48", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar" + }, + { + "coord": "org.springframework.security:spring-security-oauth2-jose:5.4.6", + "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.ow2.asm:asm:9.0", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "org.springframework:spring-context:5.3.6", + "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", + "org.springframework:spring-core:5.3.6", + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6", + "net.minidev:json-smart:2.3" + ], + "directDependencies": [ + "com.nimbusds:nimbus-jose-jwt:8.21", + "org.springframework:spring-core:5.3.6", + "org.springframework.security:spring-security-core:5.4.6", + "org.springframework.security:spring-security-oauth2-core:5.4.6" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar" + ], + "sha256": "8f5d14a402d67b0590982051f9d221c1ecfa289bd2a60c0d516b97d0a2986665", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar" + }, { "coord": "org.springframework.security:spring-security-web:5.4.6", "dependencies": [ From d1d4df552164e71294d687e7a2cefbc7c71e6212 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 May 2021 10:58:19 +0200 Subject: [PATCH 27/28] Bump @babel/preset-env from 7.14.0 to 7.14.1 (#1705) Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.14.0 to 7.14.1. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.14.1/packages/babel-preset-env) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index f38cddda1c..0ac3785603 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-object-rest-spread": "^7.13.8", "@babel/plugin-transform-spread": "^7.13.0", - "@babel/preset-env": "^7.14.0", + "@babel/preset-env": "^7.14.1", "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", "@bazel/bazelisk": "^1.8.0", diff --git a/yarn.lock b/yarn.lock index c45a4f0805..ffba82e2ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -575,10 +575,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-block-scoping@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.13.16.tgz#a9c0f10794855c63b1d629914c7dcfeddd185892" - integrity sha512-ad3PHUxGnfWF4Efd3qFuznEtZKoBp0spS+DgqzVzRPV7urEBvPLue3y2j80w4Jf2YLzZHj8TOv/Lmvdmh3b2xg== +"@babel/plugin-transform-block-scoping@^7.14.1": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.1.tgz#ac1b3a8e3d8cbb31efc6b9be2f74eb9823b74ab2" + integrity sha512-2mQXd0zBrwfp0O1moWIhPpEeTKDvxyHcnma3JATVP1l+CctWBuot6OJG8LQ4DnBj4ZZPSmlb/fm4mu47EOAnVA== dependencies: "@babel/helper-plugin-utils" "^7.13.0" @@ -860,10 +860,10 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" -"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.0.tgz#236f88cd5da625e625dd40500d4824523f50e6c5" - integrity sha512-GWRCdBv2whxqqaSi7bo/BEXf070G/fWFMEdCnmoRg2CZJy4GK06ovFuEjJrZhDRXYgBsYtxVbG8GUHvw+UWBkQ== +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.14.1": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.1.tgz#b55914e2e68885ea03f69600b2d3537e54574a93" + integrity sha512-0M4yL1l7V4l+j/UHvxcdvNfLB9pPtIooHTbEhgD/6UGyh8Hy3Bm1Mj0buzjDXATCSz3JFibVdnoJZCrlUCanrQ== dependencies: "@babel/compat-data" "^7.14.0" "@babel/helper-compilation-targets" "^7.13.16" @@ -902,7 +902,7 @@ "@babel/plugin-transform-arrow-functions" "^7.13.0" "@babel/plugin-transform-async-to-generator" "^7.13.0" "@babel/plugin-transform-block-scoped-functions" "^7.12.13" - "@babel/plugin-transform-block-scoping" "^7.13.16" + "@babel/plugin-transform-block-scoping" "^7.14.1" "@babel/plugin-transform-classes" "^7.13.0" "@babel/plugin-transform-computed-properties" "^7.13.0" "@babel/plugin-transform-destructuring" "^7.13.17" @@ -932,7 +932,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.12.13" "@babel/plugin-transform-unicode-regex" "^7.12.13" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.14.0" + "@babel/types" "^7.14.1" babel-plugin-polyfill-corejs2 "^0.2.0" babel-plugin-polyfill-corejs3 "^0.2.0" babel-plugin-polyfill-regenerator "^0.2.0" @@ -1012,10 +1012,10 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.4.4": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.0.tgz#3fc3fc74e0cdad878182e5f66cc6bcab1915a802" - integrity sha512-O2LVLdcnWplaGxiPBz12d0HcdN8QdxdsWYhz5LSeuukV/5mn2xUUc3gBeU4QBYPJ18g/UToe8F532XJ608prmg== +"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.14.1", "@babel/types@^7.4.4": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.1.tgz#095bd12f1c08ab63eff6e8f7745fa7c9cc15a9db" + integrity sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA== dependencies: "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" From 5b4ec3d6d56c702d440960193b6f3f8fa6e09525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Pr=C3=B6schel?= Date: Tue, 4 May 2021 11:10:19 +0200 Subject: [PATCH 28/28] Fixes #1710 --- VERSION | 2 +- docs/docs/changelog.md | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4863f59c36..5a03fb737b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.20.0-alpha +0.20.0 diff --git a/docs/docs/changelog.md b/docs/docs/changelog.md index 901908b451..8a81ffaff0 100644 --- a/docs/docs/changelog.md +++ b/docs/docs/changelog.md @@ -3,6 +3,57 @@ title: Changelog sidebar_label: πŸ“ Changelog --- +## 0.20.0 + +#### Changes + +- Bump @types/react from 16.9.34 to 17.0.4 [[#1658](https://github.com/airyhq/airy/pull/1658)] + +#### πŸš€ Features + +- [[#1518](https://github.com/airyhq/airy/issues/1518)] Add OIDC authentication backend [[#1623](https://github.com/airyhq/airy/pull/1623)] +- [[#1505](https://github.com/airyhq/airy/issues/1505)] Rewrite Webhook queue with Beanstalkd [[#1536](https://github.com/airyhq/airy/pull/1536)] +- [[#1687](https://github.com/airyhq/airy/issues/1687)] Kafka Prometheus exporter error on… [[#1688](https://github.com/airyhq/airy/pull/1688)] +- [[#1615](https://github.com/airyhq/airy/issues/1615)] Expose tag events via websocket [[#1624](https://github.com/airyhq/airy/pull/1624)] +- [[#1495](https://github.com/airyhq/airy/issues/1495)] Add kafka Prometheus exporter [[#1668](https://github.com/airyhq/airy/pull/1668)] +- [[#1525](https://github.com/airyhq/airy/issues/1525)] Update quick filter [[#1660](https://github.com/airyhq/airy/pull/1660)] + +#### πŸ› Bug Fixes + +- [[#1698](https://github.com/airyhq/airy/issues/1698)] Webhook config error [[#1699](https://github.com/airyhq/airy/pull/1699)] +- [[#1689](https://github.com/airyhq/airy/issues/1689)] Bug: Conversation Counter: Optimize Filter Use [[#1697](https://github.com/airyhq/airy/pull/1697)] +- [[#1665](https://github.com/airyhq/airy/issues/1665)] Fix chatplugin reconnection problem [[#1682](https://github.com/airyhq/airy/pull/1682)] +- [[#1646](https://github.com/airyhq/airy/issues/1646)] fix avatar images styling [[#1680](https://github.com/airyhq/airy/pull/1680)] +- [[#1652](https://github.com/airyhq/airy/issues/1652)] Fix rendering messages with render library [[#1675](https://github.com/airyhq/airy/pull/1675)] +- [[#1674](https://github.com/airyhq/airy/issues/1674)] Chatplugin customize problems [[#1678](https://github.com/airyhq/airy/pull/1678)] +- [[#1666](https://github.com/airyhq/airy/issues/1666)] Fix chatplugin cors config [[#1667](https://github.com/airyhq/airy/pull/1667)] + +#### πŸ“š Documentation + +- [[#1676](https://github.com/airyhq/airy/issues/1676)] fix sending messages to google source [[#1677](https://github.com/airyhq/airy/pull/1677)] +- [[#1661](https://github.com/airyhq/airy/issues/1661)] Fix token name in docs [[#1664](https://github.com/airyhq/airy/pull/1664)] + +#### 🧰 Maintenance + +- Bump @babel/preset-env from 7.14.0 to 7.14.1 [[#1705](https://github.com/airyhq/airy/pull/1705)] +- Bump webpack from 5.36.1 to 5.36.2 [[#1692](https://github.com/airyhq/airy/pull/1692)] +- Bump @babel/core from 7.13.16 to 7.14.0 [[#1685](https://github.com/airyhq/airy/pull/1685)] +- Bump @babel/preset-env from 7.13.15 to 7.14.0 [[#1684](https://github.com/airyhq/airy/pull/1684)] +- Bump webpack from 5.36.0 to 5.36.1 [[#1670](https://github.com/airyhq/airy/pull/1670)] +- Bump @bazel/typescript from 3.4.1 to 3.4.2 [[#1671](https://github.com/airyhq/airy/pull/1671)] +- Bump core-js from 3.11.0 to 3.11.1 [[#1672](https://github.com/airyhq/airy/pull/1672)] +- Bump sass from 1.32.11 to 1.32.12 [[#1673](https://github.com/airyhq/airy/pull/1673)] +- Bump webpack from 5.35.1 to 5.36.0 [[#1663](https://github.com/airyhq/airy/pull/1663)] +- Bump @types/node from 15.0.0 to 15.0.1 [[#1662](https://github.com/airyhq/airy/pull/1662)] + +#### Airy CLI + +You can download the Airy CLI for your operating system from the following links: + +[MacOS](https://airy-core-binaries.s3.amazonaws.com/0.19.1/darwin/amd64/airy) +[Linux](https://airy-core-binaries.s3.amazonaws.com/0.19.1/linux/amd64/airy) +[Windows](https://airy-core-binaries.s3.amazonaws.com/0.19.1/windows/amd64/airy.exe) + ## 0.19.0 #### Changes