From 52b6ecba93130d4f0ff82d7513132e7188bf96a0 Mon Sep 17 00:00:00 2001 From: Sandeep Puthanveetil Satheesan Date: Wed, 6 Apr 2022 14:31:59 -0500 Subject: [PATCH 01/15] Master to develop after 1.13.0 (#896) * Update CHANGELOG.md * Update version numbers in the OpenAPI documents. * Update CHANGELOG.md * Update CHANGELOG.md * Update version number in YAML file. * Point to production health and talent chooser API documentation in production. * Update CHANGELOG. * Update version number in OpenAPI spec files. * Update Building Block URL in Api Doc Dockerfile. * Minor update to CHANGELOG. * Fix Auth library dependencies versions to avoid breaking changes. * Update Events Building Block Dockerfile. * Update App Config Dockerfile. * Update Authentication Building Block Dockerfile. * Update Profile Building Block Dockerfile. * Update Contributions Building Block Dockerfile and requirements. * Update Contributions Catalog Dockerfile and requirements. * Update Logging Building Block Dockerfile. * Update version numbers in API specs. * Update CHANGELOG. * Update CHANGELOG.md * Update version number. * Update CHANGELOG.md * Update CHANGELOG.md * Update version numbers in OpenAPI specification. * turn off group authentication on image get endpoint * turn off group authentication on image get endpoint * Update Events Building Block logs and related configuration. * Update CHANGELOG. * Added more information to logs * changed the log's building block name * updated to use longDescription * updated changelog * Update CHANGELOG and verson numbers. * Update API Doc Dockerfile. * Fix CHANGELOG. * Fix CHANGELOG. * Update version numbers in SECURITY.md * Fix merge conflicts. * Update CHANGELOG.md * Update CHANGELOG. * Update Dockerfile. * Update version number in API spec files. * Updater version in SECURITY.md * Update CHANGELOG. * Update Events BB version number. * Update SECURITY.md * Update API Doc Docker file Co-authored-by: Bing Zhang Co-authored-by: YONG WOOK KIM --- CHANGELOG.md | 5 ++++- SECURITY.md | 1 + eventservice/events.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb36406b..c459c36f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [1.13.0] - 2022-04-04 ### Fixed - UI changes to 'Source Repo URL' field in catalog. [#814](https://github.com/rokwire/rokwire-building-blocks-api/issues/814) - Talent form bug fixed in Contribution Catalog. [#857](https://github.com/rokwire/rokwire-building-blocks-api/issues/857) @@ -445,7 +447,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.12.1...HEAD +[Unreleased]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.13.0...HEAD +[1.13.0]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.12.1...1.13.0 [1.12.1]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.12.0...1.12.1 [1.12.0]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.11.3...1.12.0 [1.11.3]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.11.2...1.11.3 diff --git a/SECURITY.md b/SECURITY.md index d87a62f5..2ea78eda 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.13.0 | :white_check_mark: | | 1.12.1 | :white_check_mark: | | 1.12.0 | :white_check_mark: | | 1.11.3 | :white_check_mark: | diff --git a/eventservice/events.yaml b/eventservice/events.yaml index 52c43ad2..2b5201df 100755 --- a/eventservice/events.yaml +++ b/eventservice/events.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Rokwire Events Building Block API description: Events Building Block API Documentation - version: 1.12.1 + version: 1.13.0 servers: - url: https://api.rokwire.illinois.edu description: Production server From f6305bd303c52e7df7f0159edfc15fefedc233fd Mon Sep 17 00:00:00 2001 From: Minu Mathew Date: Fri, 8 Apr 2022 00:11:47 +0530 Subject: [PATCH 02/15] 839 send email from contribution (#867) * Edits for /ok endpoint * Added ok endpoint to CHANGELOG * updated yaml to include email * added reviewer email * resolved merge conflicts * updated changelog * send email to reviewer with username * updated changelog * added appropriate spacing * added email notification for new contribution * update code if email field not present * added config and exceptions * updated get reviewers record method * inserted more exception handling * added env variable for notification * changed changelog * updated changelog * updated --- CHANGELOG.md | 5 +- contributions/api/controllers/configs.py | 6 ++ .../api/controllers/contributions.py | 91 ++++++++++++++++++- contributions/api/utils/adminutils.py | 56 ++++++++++++ contributions/api/utils/mongoutils.py | 20 ++++ 5 files changed, 174 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c459c36f..1c05a30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Sending email to reviewers. [#839](https://github.com/rokwire/rokwire-building-blocks-api/issues/839) ## [1.13.0] - 2022-04-04 ### Fixed @@ -16,10 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add a Review section to Contribution. [#756](https://github.com/rokwire/rokwire-building-blocks-api/issues/756) - Error message text to event building block when it is internal sever error. [#840](https://github.com/rokwire/rokwire-building-blocks-api/issues/840) -- Added email field for reviewers. [#839](https://github.com/rokwire/rokwire-building-blocks-api/issues/839) +- Added email field for reviewers. [#864](https://github.com/rokwire/rokwire-building-blocks-api/issues/864) - Add query filter to get events created by a user. [#873](https://github.com/rokwire/rokwire-building-blocks-api/issues/873) - Add Aquatics and Intramural tags. [#872](https://github.com/rokwire/rokwire-building-blocks-api/issues/872) - ### Changed - All group event user can GET and DELETE group event. [#847](https://github.com/rokwire/rokwire-building-blocks-api/issues/847) - CODEOWNERS file. [#826](https://github.com/rokwire/rokwire-building-blocks-api/issues/826) diff --git a/contributions/api/controllers/configs.py b/contributions/api/controllers/configs.py index c709a085..c2368f53 100644 --- a/contributions/api/controllers/configs.py +++ b/contributions/api/controllers/configs.py @@ -36,3 +36,9 @@ FIELD_NAME = 'name' ADMIN_USERS = os.getenv('ADMIN_USERS', '') + +NOTIFICATION_ENABLED = bool(os.getenv('NOTIFICATION_ENABLED', 'True') == 'True') +SMTP_HOST = os.getenv('SMTP_HOST', 'smtp.office365.com') +SMTP_PORT = os.getenv('SMTP_PORT', 587) +SENDER_EMAIL = os.getenv('SENDER_EMAIL', '') +SENDER_EMAIL_PASSWORD = os.getenv('SENDER_EMAIL_PASSWORD', '') diff --git a/contributions/api/controllers/contributions.py b/contributions/api/controllers/contributions.py index 641435c8..ee27e5a7 100644 --- a/contributions/api/controllers/contributions.py +++ b/contributions/api/controllers/contributions.py @@ -15,6 +15,7 @@ import json import datetime import logging +import re from flask import wrappers, request from bson import ObjectId @@ -42,6 +43,7 @@ db_contribution = client_contribution[cfg.CONTRIBUTION_DB_NAME] coll_contribution = db_contribution[cfg.CONTRIBUTION_COLL_NAME] coll_reviewer = db_contribution[cfg.REVIEWER_COLL_NAME] +notification_enabled = cfg.NOTIFICATION_ENABLED def post(token_info): is_new_install = True @@ -200,6 +202,12 @@ def post(token_info): msg_json = jsonutils.create_log_json("Contribution", "POST", {"id": str(contribution_id)}) logging.info("Contribution POST " + json.dumps(msg_json)) + # send new contribution email to add reviewers + if notification_enabled: + list_reviewers = mongoutils.list_reviewers() + for reviewer in list_reviewers: + send_email_new_contribution(reviewer['githubUsername'], contribution_name) + return rs_handlers.return_id(msg, 'id', contribution_id) def search(token_info=None, name=None): @@ -859,7 +867,6 @@ def admin_reviewers_post(token_info): name = in_json["name"] username = in_json["githubUsername"] email = in_json["email"] - # check if the dataset is existing with given github username dataset = mongoutils.get_dataset_from_field(coll_reviewer, "githubUsername", username) if dataset is not None: @@ -884,7 +891,10 @@ def admin_reviewers_post(token_info): logging.info("Contribution Admin POST " + json.dumps(msg_json)) reviewer_id = str(dataset['_id']) - + # send email when new reviewer is added + ### TODO : This function is to be called when a reviewer is assigned to a contribution + if notification_enabled: + send_email_new_reviewer(dataset['githubUsername']) return rs_handlers.return_id(msg, 'id', reviewer_id) def admin_reviewers_search(token_info): @@ -936,3 +946,80 @@ def admin_reviewers_delete(token_info, id): msg_json = jsonutils.create_log_json("Contribution Admin ", "DELETE", msg) logging.info("Contribution Admin DELETE " + json.dumps(msg_json)) return rs_handlers.not_found(msg_json) + +def send_email_new_reviewer(username): + """ + Method to send email to user for new reviewers + Args: + username (str) : github username of reviewer + """ + # check if the dataset is existing with given github username + dataset = mongoutils.get_reviewers_record(username) + if dataset is None: + msg = { + "reason": "Github Username not present in the database: " + str(username), + "error": "Bad Request: " + request.url, + } + msg_json = jsonutils.create_log_json("Contribution Admin", "POST", msg) + logging.error("Contribution Admin POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) + + if 'email' in dataset[0].keys(): + subject = "Reviewer updated" + message = "Reviewer has been updated for a contribution" + success, error_code, error_msg = adminutils.send_email(dataset[0]['email'], subject, message) + if not success: + msg = { + "reason": "Error in sending email via SMTP: " + str(error_msg), + "error": "Error code" + str(error_code) + } + msg_json = jsonutils.create_log_json("Contribution", "POST", msg) + logging.error("Contribution POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) + else: + msg = { + "reason": "Email not present for username " + str(username) + } + msg_json = jsonutils.create_log_json("Contribution", "POST", msg) + logging.error("Contribution POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) + +def send_email_new_contribution(username, contribution_name): + """ + Method to send email to user for new contribution + Args: + username (str) : github username of reviewer + contribution_name (str): cfg.FIELD_NAME of contribution + """ + # check if the dataset is existing with given github username + dataset = mongoutils.get_reviewers_record(username) + if dataset is None: + msg = { + "reason": "Github Username not present in the database: " + str(username), + "error": "Bad Request: " + request.url, + } + msg_json = jsonutils.create_log_json("Contribution Admin", "POST", msg) + logging.error("Contribution Admin POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) + + if 'email' in dataset[0].keys(): + subject = "New Rokwire Contribution Submitted" + message = "New contribution " + contribution_name + " has been added for your review" + success, error_code, error_msg = adminutils.send_email(dataset[0]['email'], subject, message) + if not success: + msg = { + "reason": "Error in sending email via SMTP: " + str(error_msg), + "error": "Error code" + str(error_code) + } + msg_json = jsonutils.create_log_json("Contribution", "POST", msg) + logging.error("Contribution POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) + else: + msg = { + "reason": "Email not present for Github Username in the database: " + str(username), + "error": "Bad Request: " + request.url, + } + msg_json = jsonutils.create_log_json("Contribution Admin", "POST", msg) + logging.error("Contribution Admin POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) + diff --git a/contributions/api/utils/adminutils.py b/contributions/api/utils/adminutils.py index 8a1dea08..db42b827 100644 --- a/contributions/api/utils/adminutils.py +++ b/contributions/api/utils/adminutils.py @@ -15,6 +15,10 @@ import controllers.configs as cfg import utils.mongoutils as mongoutils +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + """ check if the logged in user is a superuser """ @@ -49,3 +53,55 @@ def check_if_reviewer(login_id): return True return False + +def send_email(mail_to, subject, message): + """ + Method to send email to a user and print if success or failure + Args: + mail_to (str): email id of recipient + subject (str): subject of the email + message (str): message of the email + Returns: + (bool): True if success, False if failure + (str): Error code is failure, empty string if success + (str): Error message if failure, empty string if success + """ + mail_subject = subject + mail_body = message + + mail_from = cfg.SENDER_EMAIL + password = cfg.SENDER_EMAIL_PASSWORD + + mimemsg = MIMEMultipart() + mimemsg['From'] = mail_from + mimemsg['To'] = mail_to + mimemsg['Subject'] = mail_subject + mimemsg.attach(MIMEText(mail_body, 'plain')) + + connection = smtplib.SMTP(host=cfg.SMTP_HOST, port=cfg.SMTP_PORT) + try: + connection.ehlo() + except smtplib.SMTPHeloError as ex: + return False, ex.smtp_error, ex.smtp_code + try: + connection.starttls() + except smtplib.SMTPConnectError as ex: + return False, ex.smtp_error, ex.smtp_code + try: + connection.login(mail_from, password) + except smtplib.SMTPAuthenticationError as ex: + return False, ex.smtp_error, ex.smtp_code + try: + connection.send_message(mimemsg) + except smtplib.SMTPResponseException as ex: + return False, ex.smtp_error, ex.smtp_code + except smtplib.SMTPException as ex: + return False, ex.strerror, ex.errno + try: + connection.quit() + return True, ' ', ' ' + except smtplib.SMTPResponseException as ex: + return False, ex.smtp_error, ex.smtp_code + except smtplib.SMTPException as ex: + return False, ex.strerror, ex.errno + diff --git a/contributions/api/utils/mongoutils.py b/contributions/api/utils/mongoutils.py index 17d215f8..fb69644e 100644 --- a/contributions/api/utils/mongoutils.py +++ b/contributions/api/utils/mongoutils.py @@ -381,6 +381,26 @@ def list_reviewers(): else: return None +def get_reviewers_record(username): + """ + Method to return the record of a reviewer from mongodb reviewer collection + Args: + username (str): github username + Returns: + (json) : json output from mongodb find query + """ + db_data = coll_reviewer.find({"githubUsername": username}) + data_list = list(db_data) + + if len(data_list) > 0: + data_dump = dumps(data_list) + json_load = json.loads(data_dump) + json_load = jsonutils.convert_obejctid_from_dataset_json_list(json_load) + return json_load + else: + return None + + """ query using query field and querystring and convert result to object """ From ed8a7faa26ed9ed928435f52d3c45cac484f1245 Mon Sep 17 00:00:00 2001 From: YONG WOOK KIM Date: Thu, 7 Apr 2022 13:52:22 -0500 Subject: [PATCH 03/15] 858 saving multiple capabilities resulting in error (#868) * made javascript to add incremental values to id * modified javascript for capabilities * made capability backend to work * make error message more readable * added self-certification * fixed talent update * modified changelog * fixed min end user role's multiple selection * fixed is open code interactive show and hide * removed selection for capability in this contribution from talent's required capabilities * updated required capability and self certification * modified changelog * modified changelog * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Sandeep Puthanveetil Satheesan --- CHANGELOG.md | 13 +- .../api/controllers/contributions.py | 21 +- .../catalog/controllers/contribute.py | 14 +- .../catalog/models/capability_utilities.py | 64 +- .../catalog/models/talent_utilities.py | 69 +- .../templates/contribute/contribute.html | 2168 ++++++++--------- .../templates/contribute/talent_details.html | 153 +- 7 files changed, 1149 insertions(+), 1353 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c05a30f..d3c3cebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - Sending email to reviewers. [#839](https://github.com/rokwire/rokwire-building-blocks-api/issues/839) +- Self certification information to talent [#878](https://github.com/rokwire/rokwire-building-blocks-api/issues/878) + +### Changed +- Modified required capability in talent detail page [#877](https://github.com/rokwire/rokwire-building-blocks-api/issues/877) +- Minimum end user role as text in talent detail page [#879](https://github.com/rokwire/rokwire-building-blocks-api/issues/879) + +### Fixed +- Posting contirbuiton error when required capability is empty in talent [#874](https://github.com/rokwire/rokwire-building-blocks-api/issues/874) +- End user role in posting doesn't update multiple selection [#870](https://github.com/rokwire/rokwire-building-blocks-api/issues/870) +- Show and hide of source repo url based on the selection of open source [#869](https://github.com/rokwire/rokwire-building-blocks-api/issues/869) +- Saving multiple capabilities error [#858](https://github.com/rokwire/rokwire-building-blocks-api/issues/858) ## [1.13.0] - 2022-04-04 ### Fixed @@ -475,4 +486,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [1.0.3]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/rokwire/rokwire-building-blocks-api/compare/1.0.0...1.0.1 -[1.0.0]: https://github.com/rokwire/rokwire-building-blocks-api/releases/tag/1.0.0 \ No newline at end of file +[1.0.0]: https://github.com/rokwire/rokwire-building-blocks-api/releases/tag/1.0.0 diff --git a/contributions/api/controllers/contributions.py b/contributions/api/controllers/contributions.py index ee27e5a7..684e1035 100644 --- a/contributions/api/controllers/contributions.py +++ b/contributions/api/controllers/contributions.py @@ -370,18 +370,15 @@ def put(token_info, id): if talent.requiredCapabilities is not None: required_cap_list = talent.requiredCapabilities for capability_json in required_cap_list: - capability, rest_capability_json, msg = modelutils.construct_capability(capability_json) - if capability.id is not None: - is_uuid = otherutils.check_if_uuid(capability.id) - if not is_uuid: - msg = { - "reason": "Capability id in requiredCapabilities is not in uuid format", - "error": "Bad Request: " + request.url, - } - msg_json = jsonutils.create_log_json("Contribution", "POST", msg) - logging.error("Contribution POST " + json.dumps(msg_json)) - return rs_handlers.bad_request(msg) - + is_uuid = otherutils.check_if_uuid(capability_json["capabilityId"]) + if not is_uuid: + msg = { + "reason": "Capability id in requiredCapabilities is not in uuid format", + "error": "Bad Request: " + request.url, + } + msg_json = jsonutils.create_log_json("Contribution", "POST", msg) + logging.error("Contribution POST " + json.dumps(msg_json)) + return rs_handlers.bad_request(msg) talent_list.append(talent) contribution_dataset.set_talents(talent_list) except: diff --git a/contributions/catalog/controllers/contribute.py b/contributions/catalog/controllers/contribute.py index 338895bf..fcb5d6eb 100644 --- a/contributions/catalog/controllers/contribute.py +++ b/contributions/catalog/controllers/contribute.py @@ -451,7 +451,7 @@ def create(): return redirect(url_for('contribute.contribution_details', contribution_id=s)) elif not response: logging.error(s) - msg = "Contribution submission failed. Please try again after some time!" + msg = "Contribution submission failed. Please try again after some time! " + s if "name" in session: return render_template('contribute/error.html', user=session["name"], token=session['oauth_token']['access_token'], error_msg=msg) else: @@ -552,9 +552,15 @@ def post_contribution(json_data): if result.status_code != 200: err_json = parse_response_error(result) logging.error("Contribution POST " + json.dumps(err_json)) - err_msg = str(err_json['status']), err_json['title'], err_json['detail'] - return False, str("post method fails with error: ") + str(result.status_code) \ - + ": " + str(err_msg) + # TODO the message should be updated in more user friendly way. + if 'reason' in err_json: + return False, str("post method fails with error: ") + str(result.status_code) \ + + ": " + str(str(err_json['reason'])), err_json + elif 'detail' in err_json: + return False, str("post method fails with error: ") + str(result.status_code) \ + + ": " + str(str(err_json['detail'])), err_json + else: + return False, str("post method fails with error: ") + str(result.status_code), err_json else: # parse contribution id from response result_str = result.content.decode("utf-8").replace("\n", "") diff --git a/contributions/catalog/models/capability_utilities.py b/contributions/catalog/models/capability_utilities.py index 3c967b8b..d5232738 100644 --- a/contributions/catalog/models/capability_utilities.py +++ b/contributions/catalog/models/capability_utilities.py @@ -34,8 +34,9 @@ def init_capability(): 'environmentVariables': [] }, 'dataDeletionEndpointDetails': { - 'endpoint': '', - 'api': '' + 'deletionEndpoint': '', + 'apiKey': '', + 'description': '' }, } return d @@ -45,43 +46,58 @@ def to_capability(d): if not d: return {} capability_list = [] - # init capability - if isinstance(d['capability_name'], str): - capability_list.append(init_capability()) - else: - for _ in range(len(d['capability_name'])): + # check how many capabilities are in the given json + # this should be checked keys that is as surfix 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 = [] + # 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 + + # init capability + for _ in range(num_cap): capability_list.append(init_capability()) for i, capability in enumerate(capability_list): cap_id = str(uuid.uuid4()) capability['id'] = cap_id - env_k, env_v = d['environmentVariables_key'], d['environmentVariables_value'] + + env_k, env_v = d['environmentVariables_key_' + str(i)], d['environmentVariables_value_' + str(i)] for k, v in list(zip(env_k, env_v)): capability["deploymentDetails"]['environmentVariables'].append({'key': k, 'value': v}) for k, v in d.items(): - if "isOpenSource" in k: - if v[i] == 'y': + if "isOpenSource_" + str(i) in k: + if v[0] == 'y': capability_list[i]["isOpenSource"] = True else: capability_list[i]["isOpenSource"] = False - d[k][i] = capability_list[i]["isOpenSource"] - elif "sourceRepoUrl" in k: + d[k][0] = capability_list[i]["isOpenSource"] + elif "sourceRepoUrl_" + str(i) in k: if capability_list[i]["isOpenSource"]: - capability_list[i]["sourceRepoUrl"] = v[i] + capability_list[i]["sourceRepoUrl"] = v[0] elif "deploymentDetails_" in k: - name = k.split("deploymentDetails_")[-1] - capability_list[i]["deploymentDetails"][name] = v[i] + if ("_" + str(i)) in k: + name = (k.split("deploymentDetails_")[-1]).split('_' + str(i))[0] + capability_list[i]["deploymentDetails"][name] = v[0] elif "dataDeletionEndpointDetails_" in k: - name = k.split("dataDeletionEndpointDetails_")[-1] - capability_list[i]["dataDeletionEndpointDetails"][name] = v[i] + if ("_" + str(i)) in k: + name = (k.split("dataDeletionEndpointDetails_")[-1]).split('_' + str(i))[0] + capability_list[i]["dataDeletionEndpointDetails"][name] = v[0] elif "capability_" in k: - name = k.split("capability_")[-1] - if name in capability_list[i] and isinstance(capability_list[i][name], list) and len(v[i]) > 0: - capability_list[i][name].append(v[i]) - elif name in capability_list[i] and isinstance(capability_list[i][name], list) and len(v[i]) == 0: - capability_list[i][name] = [] - else: - capability_list[i][name] = v[i] + 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] = [] + else: + capability_list[i][name] = v[0] return capability_list diff --git a/contributions/catalog/models/talent_utilities.py b/contributions/catalog/models/talent_utilities.py index 528cf9d1..857cede7 100644 --- a/contributions/catalog/models/talent_utilities.py +++ b/contributions/catalog/models/talent_utilities.py @@ -36,42 +36,60 @@ def init_talent(): def to_talent(d): if not d: return {} talent_list = [] - if 'talent_name' in d.keys(): - if isinstance(d['talent_name'], str): + + # check how many capabilities are in the given json + # this should be checked keys that is as surfix 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 + 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 + + # init talent + for _ in range(num_tal): talent_list.append(init_talent()) - else: - for _ in range(len(d['talent_name'])): - talent_list.append(init_talent()) - - for i, talent in enumerate(talent_list): - tal_id = str(uuid.uuid4()) - talent['id'] = tal_id - - for k, v in d.items(): - # print(k, v) - if "minUserPrivacyLevel" in k: - if len(v[i]) > 0: - talent_list[i]["minUserPrivacyLevel"] = int(v[i]) - d[k][i] = talent_list[i]["minUserPrivacyLevel"] - if "talent_" in k: - name = k.split("talent_")[-1] + + for i, talent in enumerate(talent_list): + tal_id = str(uuid.uuid4()) + talent['id'] = tal_id + + for k, v in d.items(): + if "minUserPrivacyLevel_" in k: + if len(str(v[0])) > 0: + talent_list[i]["minUserPrivacyLevel"] = int(v[0]) + d[k][0] = talent_list[i]["minUserPrivacyLevel"] + if "talent_" in k: + if ("_" + str(i)) in k: + name = (k.split("talent_")[-1]).split('_' + str(i))[0] # TODO this is not a very good exercise since everything is list, # so the code only checks the very first items in the list assuming that # 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[i]) > 0: + if name in talent_list[i] and isinstance(talent_list[i][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]) + elif name == "minEndUserRoles": + for j in range(len(v)): + talent_list[i][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[i]) == 0: + elif name in talent_list[i] and isinstance(talent_list[i][name], list) and len(v[0]) == 0: talent_list[i][name] = [] else: - talent_list[i][name] = v[i] - talent_list[i]["selfCertification"] = to_self_certification(d) + talent_list[i][name] = v[0] + + talent_list[i]["selfCertification"] = to_self_certification(d, i) + return talent_list def init_self_certification(): @@ -86,13 +104,14 @@ def init_self_certification(): return d -def to_self_certification(d): +def to_self_certification(d, i): if not d: return {} res = init_self_certification() for k, v in d.items(): if "selfcertificate_" in k: - name = k.split("selfcertificate_")[-1] - res[name] = v[0] + if ("_" + str(i)) in k: + name = (k.split("selfcertificate_")[-1]).split('_' + str(i))[0] + res[name] = v[0] return res def reconstruct_required_capabilities(d): diff --git a/contributions/catalog/webapps/templates/contribute/contribute.html b/contributions/catalog/webapps/templates/contribute/contribute.html index b6014a0e..212260f3 100644 --- a/contributions/catalog/webapps/templates/contribute/contribute.html +++ b/contributions/catalog/webapps/templates/contribute/contribute.html @@ -127,8 +127,6 @@

Contribution Details

{% endif %} - -
@@ -143,8 +141,7 @@

Contribution Details

placeholder="Give a list of admin names, separated by comma" type="text">
{% endif %} -
- +
@@ -158,161 +155,8 @@

Contribution Details

- {% if post %} - {% if post.contributors %} - {% for contributor in post.contributors %} - - - - {% endfor %} - {% else %} + {% if post.contributors %} + {% for contributor in post.contributors %} - {% endif %} + {% endfor %} {% else %} @@ -516,793 +340,579 @@

Contribution Details

- {% if is_editable %} - - {% else %} - - {% endif %} +
-
- {% if is_editable %} - - {% else %} - - {% endif %} +
-
- {% if is_editable %} - - {% else %} - - {% endif %} +
- {% if is_editable %} - - {% else %} - - {% endif %} +
- {% if is_editable %} - - {% else %} - - {% endif %} +
- {% if is_editable %} - - {% else %} - - {% endif %} +
- {% if is_editable %} - - {% else %} - - {% endif %} +
- {% if is_editable %} - - {% else %} - - {% endif %} +
- {% if is_editable %} - - {% else %} - - {% endif %} +
{% endif %} + - - -
+
+ - -
- -
- - OR - -
+ + OR +
+
-
-