diff --git a/.gitignore b/.gitignore index 1e52c90f..1e2449c0 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,8 @@ authservice/credentials.env # Docker ENV files .env +# Docker xml file +**.xml # Python builds *.egg-info/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b78ed89..e858fb95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] + +## [1.16.0] - 2022-08-29 + +### Added +- Ability to delete a capability or talent from contribution. [#951](https://github.com/rokwire/rokwire-building-blocks-api/issues/951) +- Hide sensitive data in capability view page. [#950](https://github.com/rokwire/rokwire-building-blocks-api/issues/950) +- Minimum user privacy level in talent form. [#970](https://github.com/rokwire/rokwire-building-blocks-api/issues/970) + +### Security +- Upgrade Swagger UI base Docker image to v4.13.2. [#991](https://github.com/rokwire/rokwire-building-blocks-api/issues/991) + +### Changed +- Change to allow all group admins to manage group events. [#996](https://github.com/rokwire/rokwire-building-blocks-api/issues/996) + +### Fixed + + ## [1.15.0] - 2022-07-11 ### Added - Support in Contributions BB to upload an icon for Talents and Capabilities. [#945](https://github.com/rokwire/rokwire-building-blocks-api/issues/945) @@ -501,7 +518,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - References to AWS keys and variables in the Events Building Block. -[Unreleased]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.15.1...HEAD +[Unreleased]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.16.0...HEAD +[1.16.0]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.15.0...1.16.0 [1.15.0]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.14.1...1.15.0 [1.14.1]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.14.0...1.14.1 [1.14.0]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.13.0...1.14.0 diff --git a/CODEOWNERS b/CODEOWNERS index e65141f5..98b8ea8e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,7 +5,7 @@ /appconfigservice/ @minump # Authentication Middleware Library -/lib/auth-middleware/ @ywkim312 +/lib/auth-middleware/ @sandeep-ps # API Doc /Dockerfile @sandeep-ps @@ -15,14 +15,14 @@ /eventservice/ @bingzhang # Logging Building Block -/loggingservice/ @ywkim312 +/loggingservice/ @sandeep-ps # Profile Building Block -/profileservice/ @ywkim312 +/profileservice/ @sandeep-ps # Contributions Building Block -/contributions/* @ywkim312 -/contributions/api/ @ywkim312 +/contributions/* @minump +/contributions/api/ @minump # Contributions Catalog /contributions/catalog/ @minump diff --git a/Dockerfile b/Dockerfile index 9056edff..e569444c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM swaggerapi/swagger-ui:v3.28.0 +FROM swaggerapi/swagger-ui:v4.13.2 COPY appconfigservice/appconfig.yaml /usr/share/nginx/html/app/ COPY authservice/auth.yaml /usr/share/nginx/html/app/ @@ -25,5 +25,3 @@ ENV URLS "[{url: 'app/appconfig.yaml', name: 'App Config Building Block'}, {url: VOLUME /usr/share/nginx/html/app/ ENV BASE_URL="/docs" - -CMD ["sh", "/usr/share/nginx/run.sh"] diff --git a/SECURITY.md b/SECURITY.md index 02eb1d21..eb30f09e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,6 +6,7 @@ Patches for **Rokwire Building Blocks** in this repository will only be applied | Version | Supported | |----------| ------------------ | +| 1.16.0 | :white_check_mark: | | 1.15.0 | :white_check_mark: | | 1.14.1 | :white_check_mark: | | 1.14.0 | :white_check_mark: | diff --git a/appconfigservice/appconfig.yaml b/appconfigservice/appconfig.yaml index 6957ed2a..cd3a356d 100755 --- a/appconfigservice/appconfig.yaml +++ b/appconfigservice/appconfig.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Rokwire App Config Building Block API description: App Config Building Block API Documentation - version: 1.15.0 + version: 1.16.0 servers: - url: https://api.rokwire.illinois.edu description: Production server @@ -310,4 +310,4 @@ components: scheme: bearer bearerFormat: JWT x-bearerInfoFunc: auth_middleware.verify_core_token - description: The client must send a valid (i.e., signed, not expired) OpenID Connect id_token in the Authorization header including anonymous tokens \ No newline at end of file + description: The client must send a valid (i.e., signed, not expired) OpenID Connect id_token in the Authorization header including anonymous tokens diff --git a/contributions/catalog/models/capability_utilities.py b/contributions/catalog/models/capability_utilities.py index 3cfcce20..4abd6030 100644 --- a/contributions/catalog/models/capability_utilities.py +++ b/contributions/catalog/models/capability_utilities.py @@ -48,25 +48,27 @@ def to_capability(d): capability_list = [] # check how many capabilities are in the given json - # this should be checked keys that is as surfix of _number + # this should be checked keys that is as suffix of _number num_cap = 0 - # if there is capability_name_0, it means that there is capability - if "capability_name_0" in d: - keys = list(d.keys()) - cap_len = [] + # if there is capability_name_{num}, it means that there is capability + capability_pattern = re.compile('capability_name_[0-9]') + keys = list(d.keys()) + if any(capability_pattern.match(key) for key in keys): + cap_indexes = [] # iterate to count the number of capabilities for key in keys: key_splitted = key.split("capability_name_") if len(key_splitted) > 1: - cap_len.append(int(key_splitted[1])) - num_cap = max(cap_len) + 1 + cap_indexes.append(int(key_splitted[1])) + num_cap = len(cap_indexes) # init capability for _ in range(num_cap): capability_list.append(init_capability()) - for i, capability in enumerate(capability_list): + for ind, capability in enumerate(capability_list): cap_id = str(uuid.uuid4()) capability['id'] = cap_id + i = cap_indexes[ind] # get environment key value pairs by pattern matching. # filter by matching with pattern environmentVariables_key_{{env_num}}_{{cap_num}} key_pattern = re.compile('environmentVariables_key_[0-9]+' + '_' + str(i)) @@ -80,29 +82,29 @@ def to_capability(d): for k, v in d.items(): if "isOpenSource_" + str(i) in k: if v[0] == 'y': - capability_list[i]["isOpenSource"] = True + capability_list[ind]["isOpenSource"] = True else: - capability_list[i]["isOpenSource"] = False - d[k][0] = capability_list[i]["isOpenSource"] + capability_list[ind]["isOpenSource"] = False + d[k][0] = capability_list[ind]["isOpenSource"] elif "sourceRepoUrl_" + str(i) in k: - if capability_list[i]["isOpenSource"]: - capability_list[i]["sourceRepoUrl"] = v[0] + if capability_list[ind]["isOpenSource"]: + capability_list[ind]["sourceRepoUrl"] = v[0] elif "deploymentDetails_" in k: if ("_" + str(i)) in k: name = (k.split("deploymentDetails_")[-1]).split('_' + str(i))[0] - capability_list[i]["deploymentDetails"][name] = v[0] + capability_list[ind]["deploymentDetails"][name] = v[0] elif "dataDeletionEndpointDetails_" in k: if ("_" + str(i)) in k: name = (k.split("dataDeletionEndpointDetails_")[-1]).split('_' + str(i))[0] - capability_list[i]["dataDeletionEndpointDetails"][name] = v[0] + capability_list[ind]["dataDeletionEndpointDetails"][name] = v[0] elif "capability_" in k: if ("_" + str(i)) in k: name = (k.split("capability_")[-1]).split('_' + str(i))[0] - if name in capability_list[i] and isinstance(capability_list[i][name], list) and len(v[0]) > 0: - capability_list[i][name].append(v[0]) - elif name in capability_list[i] and isinstance(capability_list[i][name], list) and len(v[0]) == 0: - capability_list[i][name] = [] + if name in capability_list[ind] and isinstance(capability_list[ind][name], list) and len(v[0]) > 0: + capability_list[ind][name].append(v[0]) + elif name in capability_list[ind] and isinstance(capability_list[ind][name], list) and len(v[0]) == 0: + capability_list[ind][name] = [] else: - capability_list[i][name] = v[0] + capability_list[ind][name] = v[0] return capability_list diff --git a/contributions/catalog/models/talent_utilities.py b/contributions/catalog/models/talent_utilities.py index 38bfafc2..ec7d7f0d 100644 --- a/contributions/catalog/models/talent_utilities.py +++ b/contributions/catalog/models/talent_utilities.py @@ -15,6 +15,7 @@ from datetime import date import uuid import json +import re def init_talent(): d = { @@ -39,28 +40,28 @@ def to_talent(d): talent_list = [] # check how many capabilities are in the given json - # this should be checked keys that is as surfix of _number + # this should be checked keys that is as suffix of _number num_tal = 0 - - # if there is talent_name_0, this means that there is talent - if 'talent_name_0' in d.keys(): - keys = list(d.keys()) - tal_len = [] - # iterated talents to see how many talents are in there + # if there is capability_name_{num}, it means that there is capability + talent_pattern = re.compile('talent_name_[0-9]') + keys = list(d.keys()) + if any(talent_pattern.match(key) for key in keys): + tal_indexes = [] + # iterate to count the number of capabilities for key in keys: key_splitted = key.split("talent_name_") if len(key_splitted) > 1: - tal_len.append(int(key_splitted[1])) - num_tal = max(tal_len) + 1 + tal_indexes.append(int(key_splitted[1])) + num_tal = len(tal_indexes) - # init talent + # init capability for _ in range(num_tal): talent_list.append(init_talent()) - for i, talent in enumerate(talent_list): + for ind, talent in enumerate(talent_list): tal_id = str(uuid.uuid4()) talent['id'] = tal_id - + i = tal_indexes[ind] for k, v in d.items(): if "minUserPrivacyLevel_" in k: if len(str(v[0])) > 0: @@ -74,25 +75,25 @@ def to_talent(d): # the items are only single item entry. # However, required capabilities should be a list so it should be handled differently, # and if there is any item that is a list, that should be handled separately. - if name in talent_list[i] and isinstance(talent_list[i][name], list) and len(v[0]) > 0: + if name in talent_list[ind] and isinstance(talent_list[ind][name], list) and len(v[0]) > 0: if name == "requiredCapabilities": for j in range(len(v)): v[j] = reconstruct_required_capabilities(v[j]) - talent_list[i][name].append(v[j]) + talent_list[ind][name].append(v[j]) elif name == "requiredBuildingBlocks": for j in range(len(v)): - talent_list[i][name].append(v[j]) + talent_list[ind][name].append(v[j]) elif name == "minEndUserRoles": for j in range(len(v)): - talent_list[i][name].append(v[j]) + talent_list[ind][name].append(v[j]) else: - talent_list[i][name].append(v[i]) - elif name in talent_list[i] and isinstance(talent_list[i][name], list) and len(v[0]) == 0: - talent_list[i][name] = [] + talent_list[ind][name].append(v[i]) + elif name in talent_list[ind] and isinstance(talent_list[ind][name], list) and len(v[0]) == 0: + talent_list[ind][name] = [] else: - talent_list[i][name] = v[0] + talent_list[ind][name] = v[0] - talent_list[i]["selfCertification"] = to_self_certification(d, i) + talent_list[ind]["selfCertification"] = to_self_certification(d, i) return talent_list diff --git a/contributions/catalog/webapps/static/css/style.css b/contributions/catalog/webapps/static/css/style.css index 03c5faa5..0792e327 100644 --- a/contributions/catalog/webapps/static/css/style.css +++ b/contributions/catalog/webapps/static/css/style.css @@ -389,4 +389,7 @@ hr.dotted { position: absolute; margin-left: -20px; margin-top: -20px; -} \ No newline at end of file +} + +.hidetext { -webkit-text-security: disc; } +.showtext { -webkit-text-security: none; } \ No newline at end of file diff --git a/contributions/catalog/webapps/templates/contribute/capability_details.html b/contributions/catalog/webapps/templates/contribute/capability_details.html index 7e6a89eb..ec05e03e 100644 --- a/contributions/catalog/webapps/templates/contribute/capability_details.html +++ b/contributions/catalog/webapps/templates/contribute/capability_details.html @@ -3,6 +3,7 @@
+ @@ -141,7 +142,14 @@{{key}}: {{val}} | + {% if loop.index %2 == 0 %} +{{key}}: | +{{val}} | ++ {% else %} + | {{key}}: | +{{val}} | + {% endif %}