From 1ea45334d17a9ef721dce17f41ad9f0c52d15b02 Mon Sep 17 00:00:00 2001 From: YONG WOOK KIM Date: Fri, 24 Jun 2022 16:02:59 -0500 Subject: [PATCH 1/3] added icon posting function --- contributions/catalog/controllers/config.py | 1 + .../catalog/controllers/contribute.py | 66 +++++++++++++++++++ .../contribute/capability_details.html | 9 +++ .../templates/contribute/contribute.html | 11 ++++ 4 files changed, 87 insertions(+) diff --git a/contributions/catalog/controllers/config.py b/contributions/catalog/controllers/config.py index 6362333e..71ce0975 100644 --- a/contributions/catalog/controllers/config.py +++ b/contributions/catalog/controllers/config.py @@ -41,3 +41,4 @@ class Config(object): CORS_ENABLED = bool(os.getenv('CORS_ENABLED', 'False') == 'True') ADMIN_USERS = os.getenv('ADMIN_USERS', '') CATALOG_PORT = int(os.getenv('CATALOG_PORT', '5000')) + CONTENT_BB_IMAGE_ENDPOINT_URL = os.getenv('CONTENT_BB_IMAGE_ENDPOINT_URL', 'https://api-dev.rokwire.illinois.edu/content/image') diff --git a/contributions/catalog/controllers/contribute.py b/contributions/catalog/controllers/contribute.py index 2858c08e..8f4c5887 100644 --- a/contributions/catalog/controllers/contribute.py +++ b/contributions/catalog/controllers/contribute.py @@ -17,6 +17,7 @@ import traceback import requests import datetime +import tempfile from flask import ( Blueprint, render_template, request, session, redirect, url_for @@ -456,6 +457,46 @@ def create(): # add contributionAdmins to the json_contribution contribution = jsonutil.add_contribution_admins(contribution) contribution["status"] = "Submitted" + + temp_dir = tempfile.gettempdir() + # grab file information from request. + # currently, it is only icon for either capability or talent + # if there are other file contents added in the catalog, this should be updated + for i in range(len(contribution["capabilities"])): + file = request.files["capability_icon_" + str(i)] + if file.filename != "": + # save the file to temp folder + tmp_filename = os.path.join(temp_dir, file.filename) + file.save(tmp_filename) + # upload to content building block + uploaded_url = upload_image_to_content_bb(tmp_filename) + if uploaded_url != "": + # record to the contribution + contribution["capabilities"][i]["icon"] = uploaded_url + else: + os.remove(tmp_filename) + s = "Failed to upload icon image." + return render_template('contribute/error.html', error_msg=s) + # delete tmp file + os.remove(tmp_filename) + for i in range(len(contribution["talents"])): + file = request.files["talent_icon_" + str(i)] + if file.filename != "": + # save the file to temp folder + tmp_filename = os.path.join(temp_dir, file.filename) + file.save(tmp_filename) + # upload to content building block + uploaded_url = upload_image_to_content_bb(tmp_filename) + if uploaded_url != "": + # record to the contribution + contribution["talents"][i]["icon"] = uploaded_url + else: + os.remove(tmp_filename) + s = "Failed to upload icon image." + return render_template('contribute/error.html', error_msg=s) + # delete tmp file + os.remove(tmp_filename) + json_contribution = json.dumps(contribution, indent=4) response, s, post_json = post_contribution(json_contribution) @@ -781,3 +822,28 @@ def parse_response_error(response): err_json = json.loads(err_content) return err_json + + +""" +upload image to content building block +""" +def upload_image_to_content_bb(tmp_filename): + access_token = "Bearer " + headers = {"Authorization": access_token} + + files = { + 'path': (None, '"/tmp/tmp_folder"'), + 'fileName': open(tmp_filename, 'rb'), + } + + response = requests.post(cfg.CONTENT_BB_IMAGE_ENDPOINT_URL, headers=headers, files=files) + + if response.status_code == 200: + url_json = json.loads(response.content.decode("utf-8")) + return url_json["url"] + else: + return "" + + # for testing purpose + # url_str = '{"url":"https://rokwire-images.s3.us-east-2.amazonaws.com/%22/tmp/tmp_folder%22/d35ce75c-f3fd-11ec-afd0-0a58a9feac02.webp"}' + # url_json = json.loads(url_str) diff --git a/contributions/catalog/webapps/templates/contribute/capability_details.html b/contributions/catalog/webapps/templates/contribute/capability_details.html index 7e6a89eb..f1b0c04f 100644 --- a/contributions/catalog/webapps/templates/contribute/capability_details.html +++ b/contributions/catalog/webapps/templates/contribute/capability_details.html @@ -38,6 +38,15 @@

Capability description

{{post.description}}

+ {% if post.icon %} +
+
+

Icon

+
+

{{post.icon}}

+
+ {% endif %} +

Is code open source?

diff --git a/contributions/catalog/webapps/templates/contribute/contribute.html b/contributions/catalog/webapps/templates/contribute/contribute.html index ab6da2ec..713e08a8 100644 --- a/contributions/catalog/webapps/templates/contribute/contribute.html +++ b/contributions/catalog/webapps/templates/contribute/contribute.html @@ -1094,6 +1094,11 @@

Add a Talent to this Contribution

placeholder="" type="text">
+
+ + +
@@ -1227,6 +1232,12 @@

Add a Talent to this Contribution

type="text" value="{{ talent|filter_nested_dict(["shortDescription"]) }}">
+
+ + +
From 51f0226aeb192c736aaa32e1ff40283156709df0 Mon Sep 17 00:00:00 2001 From: YONG WOOK KIM Date: Fri, 24 Jun 2022 16:04:53 -0500 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c3c3135..9c4df563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support in Contributions BB to upload an icon for Talents and Capabilities. [#945](https://github.com/rokwire/rokwire-building-blocks-api/issues/945) - Added error message when the Contributions are not retrieved from the Contributions BB [#923](https://github.com/rokwire/rokwire-building-blocks-api/issues/923) - Delete contribution button. [#944](https://github.com/rokwire/rokwire-building-blocks-api/issues/944) +- Upload image icons for Talents and Capabilities from the Catalog. [#952](https://github.com/rokwire/rokwire-building-blocks-api/issues/952) ### Changed - Display of Talent Self Certification fields when empty. [#913](https://github.com/rokwire/rokwire-building-blocks-api/issues/913) From 8a9f52c60f2d3b1c796b2e653bae6ae3b7842619 Mon Sep 17 00:00:00 2001 From: YONG WOOK KIM Date: Thu, 30 Jun 2022 14:12:21 -0500 Subject: [PATCH 3/3] added editing ability for icons --- CHANGELOG.md | 1 + .../catalog/controllers/contribute.py | 116 ++++++++++++------ .../catalog/models/capability_utilities.py | 6 +- .../catalog/models/talent_utilities.py | 8 +- .../templates/contribute/contribute.html | 25 ++++ 5 files changed, 113 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4df563..5ed01aa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added error message when the Contributions are not retrieved from the Contributions BB [#923](https://github.com/rokwire/rokwire-building-blocks-api/issues/923) - Delete contribution button. [#944](https://github.com/rokwire/rokwire-building-blocks-api/issues/944) - Upload image icons for Talents and Capabilities from the Catalog. [#952](https://github.com/rokwire/rokwire-building-blocks-api/issues/952) +- Editing image icons for Talents and Capabilities from the Catalog. [#959](https://github.com/rokwire/rokwire-building-blocks-api/issues/959) ### Changed - Display of Talent Self Certification fields when empty. [#913](https://github.com/rokwire/rokwire-building-blocks-api/issues/913) diff --git a/contributions/catalog/controllers/contribute.py b/contributions/catalog/controllers/contribute.py index 8f4c5887..43fdd072 100644 --- a/contributions/catalog/controllers/contribute.py +++ b/contributions/catalog/controllers/contribute.py @@ -19,6 +19,7 @@ import datetime import tempfile +from operator import itemgetter from flask import ( Blueprint, render_template, request, session, redirect, url_for ) @@ -200,6 +201,31 @@ def contribution_edit(contribution_id): contribution = jsonutil.add_contribution_admins(contribution, is_edit=True) # remove id from json_data del contribution["id"] + + # when it is put, since icon doesn't belong to the regular request, + # it has to be from the actual database if there is the icon value is there. + existing_contribution = get_contribution(contribution_id) + + # insert icon information into request contribution + existing_capabilities = existing_contribution["capabilities"] + existing_talents = existing_contribution["talents"] + + # match the capability and talent id and insert icon url to contribution + for existing_cap in existing_capabilities: + for i, cap in enumerate(contribution["capabilities"]): + if existing_cap["id"] == cap["id"]: + contribution["capabilities"][i]["icon"] = existing_cap["icon"] + for existing_tal in existing_talents: + for i, tal in enumerate(contribution["talents"]): + if existing_tal["id"] == tal["id"]: + contribution["talents"][i]["icon"] = existing_tal["icon"] + + # upload and update icon if there is icon image + contribution = check_and_post_image(request, contribution) + if contribution is None: + s = "Failed to upload icon image." + return render_template('contribute/error.html', error_msg=s) + json_contribution = json.dumps(contribution, indent=4) response, s = put_contribution(json_contribution, contribution_id) @@ -458,44 +484,11 @@ def create(): contribution = jsonutil.add_contribution_admins(contribution) contribution["status"] = "Submitted" - temp_dir = tempfile.gettempdir() - # grab file information from request. - # currently, it is only icon for either capability or talent - # if there are other file contents added in the catalog, this should be updated - for i in range(len(contribution["capabilities"])): - file = request.files["capability_icon_" + str(i)] - if file.filename != "": - # save the file to temp folder - tmp_filename = os.path.join(temp_dir, file.filename) - file.save(tmp_filename) - # upload to content building block - uploaded_url = upload_image_to_content_bb(tmp_filename) - if uploaded_url != "": - # record to the contribution - contribution["capabilities"][i]["icon"] = uploaded_url - else: - os.remove(tmp_filename) - s = "Failed to upload icon image." - return render_template('contribute/error.html', error_msg=s) - # delete tmp file - os.remove(tmp_filename) - for i in range(len(contribution["talents"])): - file = request.files["talent_icon_" + str(i)] - if file.filename != "": - # save the file to temp folder - tmp_filename = os.path.join(temp_dir, file.filename) - file.save(tmp_filename) - # upload to content building block - uploaded_url = upload_image_to_content_bb(tmp_filename) - if uploaded_url != "": - # record to the contribution - contribution["talents"][i]["icon"] = uploaded_url - else: - os.remove(tmp_filename) - s = "Failed to upload icon image." - return render_template('contribute/error.html', error_msg=s) - # delete tmp file - os.remove(tmp_filename) + contribution = check_and_post_image(request, contribution) + + if contribution is None: + s = "Failed to upload icon image." + return render_template('contribute/error.html', error_msg=s) json_contribution = json.dumps(contribution, indent=4) response, s, post_json = post_contribution(json_contribution) @@ -823,11 +816,58 @@ def parse_response_error(response): return err_json +""" +check if there is image and post +""" +def check_and_post_image(request, in_dict): + temp_dir = tempfile.gettempdir() + del_files = [] # list for holding the path for files to be deleted + # grab file information from request. + # currently, it is only icon for either capability or talent + # if there are other file contents added in the catalog, this should be updated + for i in range(len(in_dict["capabilities"])): + file = request.files["capability_icon_" + str(i)] + if file.filename != "": + # save the file to temp folder + tmp_filename = os.path.join(temp_dir, file.filename) + file.save(tmp_filename) + del_files.append(tmp_filename) + # upload to content building block + uploaded_url = upload_image_to_content_bb(tmp_filename) + if uploaded_url != "": + # record to the contribution + in_dict["capabilities"][i]["icon"] = uploaded_url + else: + return None + for i in range(len(in_dict["talents"])): + file = request.files["talent_icon_" + str(i)] + if file.filename != "": + # save the file to temp folder + tmp_filename = os.path.join(temp_dir, file.filename) + file.save(tmp_filename) + del_files.append(tmp_filename) + # upload to content building block + uploaded_url = upload_image_to_content_bb(tmp_filename) + if uploaded_url != "": + # record to the contribution + in_dict["talents"][i]["icon"] = uploaded_url + else: + return None + + # delete tmp files + for file in del_files: + try: + os.remove(file) + except: + print("failed to delete " + file) + return in_dict """ upload image to content building block """ def upload_image_to_content_bb(tmp_filename): + # TODO the method for gettincg access token should be developed. + # Then the toke should be inserted in the following line access_token = "Bearer " headers = {"Authorization": access_token} diff --git a/contributions/catalog/models/capability_utilities.py b/contributions/catalog/models/capability_utilities.py index 3cfcce20..bb7773cb 100644 --- a/contributions/catalog/models/capability_utilities.py +++ b/contributions/catalog/models/capability_utilities.py @@ -65,8 +65,6 @@ def to_capability(d): 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 # 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)) @@ -105,4 +103,8 @@ def to_capability(d): else: capability_list[i][name] = v[0] + # if the request is post, id should be generated + if capability_list[i]["id"] == "": + capability['id'] = str(uuid.uuid4()) + return capability_list diff --git a/contributions/catalog/models/talent_utilities.py b/contributions/catalog/models/talent_utilities.py index 38bfafc2..8d284695 100644 --- a/contributions/catalog/models/talent_utilities.py +++ b/contributions/catalog/models/talent_utilities.py @@ -58,9 +58,6 @@ def to_talent(d): 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(): if "minUserPrivacyLevel_" in k: if len(str(v[0])) > 0: @@ -94,6 +91,11 @@ def to_talent(d): talent_list[i]["selfCertification"] = to_self_certification(d, i) + # if the request is post, id should be generated + if talent_list[i]["id"] == "": + tal_id = str(uuid.uuid4()) + talent['id'] = tal_id + return talent_list def init_self_certification(): diff --git a/contributions/catalog/webapps/templates/contribute/contribute.html b/contributions/catalog/webapps/templates/contribute/contribute.html index 713e08a8..9ef31748 100644 --- a/contributions/catalog/webapps/templates/contribute/contribute.html +++ b/contributions/catalog/webapps/templates/contribute/contribute.html @@ -506,6 +506,10 @@

Add a Capability to this Contribution

+
@@ -661,11 +665,18 @@

Add a Capability to this Contribution

{% if is_editable %} + {% else %} + @@ -692,6 +703,9 @@

Add a Capability to this Contribution

capability +
+ {{ capability | filter_nested_dict(["icon"]) }} +
@@ -1080,6 +1094,10 @@

Add a Capability to this Contribution