Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

952 upload image icons for talents and capabilities from the catalog #957

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ 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)
- Editing image icons for Talents and Capabilities from the Catalog. [#959](https://github.com/rokwire/rokwire-building-blocks-api/issues/959)
- Add support for hybrid events in Events BB. [#955](https://github.com/rokwire/rokwire-building-blocks-api/issues/955)

### Changed
Expand Down
1 change: 1 addition & 0 deletions contributions/catalog/controllers/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
106 changes: 106 additions & 0 deletions contributions/catalog/controllers/contribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import traceback
import requests
import datetime
import tempfile

from operator import itemgetter
from flask import (
Blueprint, render_template, request, session, redirect, url_for
)
Expand Down Expand Up @@ -199,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)

Expand Down Expand Up @@ -456,6 +483,13 @@ def create():
# add contributionAdmins to the json_contribution
contribution = jsonutil.add_contribution_admins(contribution)
contribution["status"] = "Submitted"

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)

Expand Down Expand Up @@ -781,3 +815,75 @@ def parse_response_error(response):
err_json = json.loads(err_content)

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}

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)
6 changes: 4 additions & 2 deletions contributions/catalog/models/capability_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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
8 changes: 5 additions & 3 deletions contributions/catalog/models/talent_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ <h4>Capability description </h4>
<p class="col-sm-9">{{post.description}}</p>
</div>

{% if post.icon %}
<div class="row">
<div class="col-12 col-sm-2">
<h4>Icon </h4>
</div>
<p class="col-sm-9">{{post.icon}}</p>
</div>
{% endif %}

<div class="row">
<div class="col-12 col-sm-2">
<h4>Is code open source?</h4>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,10 @@ <h3 id="capability">Add a Capability to this Contribution</h3>
<div class="form-group">
<label class="required control-label col-sm-2">Capability Name</label>
<div class="col-sm-10">
<input type="hidden"
id="capability_id"
name="capability_id"
value="">
<input class="form-control" id="capability_name" name="capability_name"
placeholder="Give a name for your capability" type="text">
</div>
Expand Down Expand Up @@ -661,11 +665,18 @@ <h3 id="capability">Add a Capability to this Contribution</h3>
<label class="required control-label col-sm-2">Capability Name</label>
<div class="col-sm-10">
{% if is_editable %}
<input type="hidden"
id="capability_id_{{loop.index0}}"
name="capability_id_{{loop.index0}}"
value="{{ capability | filter_nested_dict(["id"]) }}">
<input class="form-control" id="capability_name_{{loop.index0}}"
name="capability_name_{{loop.index0}}"
placeholder="Give a name for your capability"
type="text" value="{{ capability | filter_nested_dict(["name"]) }}">
{% else %}
<input type="hidden"
id="capability_id_{{loop.index0}}"
name="capability_id_{{loop.index0}}">
<input class="form-control" id="capability_name_{{loop.index0}}"
name="capability_name_{{loop.index0}}"
placeholder="Give a name for your capability" type="text">
Expand All @@ -692,6 +703,9 @@ <h3 id="capability">Add a Capability to this Contribution</h3>
capability</label>
<input accept="image/*" id="capability_icon_{{loop.index0}}"
name="capability_icon_{{loop.index0}}" type="file">
<div>
{{ capability | filter_nested_dict(["icon"]) }}
</div>
</div>
<div class="form-group" id="open-source-check-div">
<label class="required control-label col-sm-2">Is the Code Open Sourced? </label>
Expand Down Expand Up @@ -1080,6 +1094,10 @@ <h3 id="capability">Add a Capability to this Contribution</h3>
<div id="talent-div-clean" style="display: none">
<hr class="dotted">
<h3>Add a Talent to this Contribution</h3>
<input type="hidden"
id="talent_id"
name="talent_id"
value="">
<div class="form-group">
<label class="required control-label col-sm-2">Talent Name</label>
<div class="col-sm-10">
Expand All @@ -1094,6 +1112,11 @@ <h3>Add a Talent to this Contribution</h3>
placeholder="" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="talent_icon">Upload an ICON for
talent</label>
<input accept="image/*" id="talent_icon" name="talent_icon" type="file">
</div>
<div class="form-group">
<label class="control-label col-sm-2">Required Building Block(s)</label>
<div class="col-sm-10">
Expand Down Expand Up @@ -1207,6 +1230,10 @@ <h3>Self-certification</h3>
<div id="talent-div-existing-records" style="display: block">
<hr class="dotted">
<h3>Add a Talent to this Contribution</h3>
<input type="hidden"
id="talent_id_{{loop.index0}}"
name="talent_id_{{loop.index0}}"
value="{{ talent|filter_nested_dict(["id"]) }}">
<div class="form-group">
<label class="required control-label col-sm-2">Talent Name</label>
<div class="col-sm-10">
Expand All @@ -1227,6 +1254,15 @@ <h3>Add a Talent to this Contribution</h3>
type="text" value="{{ talent|filter_nested_dict(["shortDescription"]) }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="talent_icon">Upload an ICON for
talent</label>
<input accept="image/*" id="talent_icon_{{loop.index0}}"
name="talent_icon_{{loop.index0}}" type="file">
<div>
{{ talent | filter_nested_dict(["icon"]) }}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Required Building Block(s)</label>
<div class="col-sm-10">
Expand Down