-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CE-116] Enable user profile get/update
Add user profile get/update support Add test case for user profile Change-Id: I5fbcc4814554a8da9827fd6b4ceb33a381249f98 Signed-off-by: Haitao Yue <hightall@me.com>
- Loading branch information
Showing
17 changed files
with
500 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
|
||
# Copyright IBM Corp, All Rights Reserved. | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
import re | ||
|
||
|
||
class StringValidator(object): | ||
# email borrowed from chenglee's validator | ||
REGEX_EMAIL = re.compile( | ||
'^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}~]+@([-0-9A-Z]+\.)+([0-9A-Z]){2,4}$', | ||
re.IGNORECASE) | ||
REGEX_ALPHA = re.compile('^[a-z]+$', re.IGNORECASE) | ||
REGEX_TLD = re.compile('([a-z\-0-9]+\.)?([a-z\-0-9]+)\.([a-z]+)$', | ||
re.IGNORECASE) | ||
REGEX_HANDLE = re.compile('[a-z0-9\_]+$', re.IGNORECASE) | ||
|
||
def validate(self, input, checks=[], log=False): | ||
|
||
results = {} | ||
fail = False | ||
|
||
# pass the input to the given checks one by one | ||
for check in checks: | ||
try: | ||
if isinstance(check, tuple): | ||
check_name = check[0] | ||
args = check[slice(1, len(check))] | ||
else: | ||
check_name = check | ||
args = None | ||
|
||
method = getattr(self, '_check_' + check_name) | ||
results[check] = method(input.strip(), | ||
args) if args else method(input) | ||
|
||
if not results[check]: | ||
if log: | ||
fail = True | ||
else: | ||
return False | ||
|
||
except Exception as e: | ||
raise | ||
|
||
return True if not fail else results | ||
|
||
def _check_not_empty(self, input): | ||
"""Check if a given string is empty""" | ||
return False if not input else True | ||
|
||
def _check_is_numeric(self, input): | ||
"""Check if a given string is numeric""" | ||
try: | ||
float(input) | ||
return True | ||
except Exception as e: | ||
return False | ||
|
||
def _check_is_alpha(self, input): | ||
"""Check if a given string is alpha only""" | ||
return True if self.REGEX_ALPHA.match(input) else False | ||
|
||
def _check_is_alphanumeric(self, input): | ||
"""Check if a given string is alphanumeric""" | ||
return True if input.isalnum() else False | ||
|
||
def _check_is_integer(self, input): | ||
"""Check if a given string is integer""" | ||
try: | ||
int(input) | ||
return True | ||
except Exception as e: | ||
return False | ||
|
||
def _check_is_float(self, input): | ||
"""Check if a given string is float""" | ||
try: | ||
return True if str(float(input)) == input else False | ||
except Exception as e: | ||
return False | ||
|
||
def _check_longer_than(self, input, args): | ||
"""Check if a given string is longer than n""" | ||
return True if len(input) > args[0] else False | ||
|
||
def _check_shorter_than(self, input, args): | ||
"""Check if a given string is shorter than n""" | ||
return True if len(input) < args[0] else False | ||
|
||
def _check_is_email(self, input): | ||
"""Check if a given string is a valid email""" | ||
return True if self.REGEX_EMAIL.match(input) else False | ||
|
||
def _check_is_tld(self, input): | ||
"""Check if a given string is a top level domain | ||
(only matches formats aaa.bbb and ccc.aaa.bbb)""" | ||
return True if self.REGEX_TLD.match(input) else False | ||
|
||
def _check_is_handle(self, input): | ||
"""Check if a given string is a username | ||
handle (alpha-numeric-underscore)""" | ||
return True if self.REGEX_HANDLE.match(input) else False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ | |
DeleteUser, UserInfo | ||
from .auth import Register, Login | ||
from .user import User | ||
from .profile import UserProfile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
|
||
# Copyright IBM Corp, All Rights Reserved. | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
from flask_restful import Resource, fields, marshal_with, reqparse | ||
from flask_login import login_required | ||
import logging | ||
import sys | ||
import os | ||
|
||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) | ||
from common import log_handler, LOG_LEVEL, StringValidator | ||
from modules.user.user import User | ||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(LOG_LEVEL) | ||
logger.addHandler(log_handler) | ||
|
||
|
||
class ValidationError(Exception): | ||
pass | ||
|
||
|
||
def email(email_str): | ||
""" | ||
Email Field to validate input email string | ||
:param email_str: email address | ||
:return: email address string or raise exception | ||
""" | ||
validator = StringValidator() | ||
if validator.validate(email_str, ["is_email"]): | ||
return email_str | ||
else: | ||
raise ValidationError("{} not a valid email".format(email_str)) | ||
|
||
|
||
user_profile_fields = { | ||
"username": fields.String, | ||
"name": fields.String, | ||
"email": fields.String, | ||
"bio": fields.String, | ||
"url": fields.String, | ||
"location": fields.String | ||
} | ||
|
||
profile_response_fields = { | ||
"result": fields.Nested(user_profile_fields), | ||
"success": fields.Boolean, | ||
"error": fields.String | ||
} | ||
|
||
update_response_fields = { | ||
"success": fields.Boolean, | ||
"error": fields.String | ||
} | ||
|
||
update_profile_parser = reqparse.RequestParser() | ||
update_profile_parser.add_argument('name', | ||
location='form', | ||
help='name for update') | ||
update_profile_parser.add_argument('email', | ||
type=email, | ||
location='form', | ||
help='email for update') | ||
update_profile_parser.add_argument('bio', | ||
location='form', | ||
help='bio for update') | ||
update_profile_parser.add_argument('url', | ||
location='form', | ||
help='url for update') | ||
update_profile_parser.add_argument('location', | ||
location='form', | ||
help='location for update') | ||
|
||
|
||
class UserProfile(Resource): | ||
""" | ||
User Profile class, supply get/put method | ||
""" | ||
@marshal_with(profile_response_fields) | ||
def get(self, user_id): | ||
""" | ||
Get user profile information | ||
:param user_id: user id of User to query | ||
:return: profile data, status code | ||
""" | ||
user_obj = User() | ||
user = user_obj.get_by_id(user_id) | ||
if not user: | ||
return {"error": "No such User", "success": False}, 400 | ||
|
||
data = { | ||
"result": { | ||
"username": user.username, | ||
"name": user.profile.name if user.profile else "", | ||
"email": user.profile.email if user.profile else "", | ||
"bio": user.profile.bio if user.profile else "", | ||
"url": user.profile.url if user.profile else "", | ||
"location": user.profile.location if user.profile else "", | ||
}, | ||
"success": True | ||
} | ||
|
||
return data, 200 | ||
|
||
@marshal_with(update_response_fields) | ||
def put(self, user_id): | ||
""" | ||
Update user profile | ||
:param user_id: user id of User to update profile | ||
:return: api response, status code | ||
""" | ||
args = update_profile_parser.parse_args() | ||
name, email_addr = args["name"], args["email"] | ||
bio, url = args["bio"], args["url"] | ||
location = args["location"] | ||
user_obj = User() | ||
user = user_obj.get_by_id(user_id) | ||
if not user: | ||
return {"error": "No such User", "success": False}, 400 | ||
else: | ||
user.update_profile(name=name, email=email_addr, | ||
bio=bio, url=url, location=location) | ||
return {"success": True}, 200 |
Oops, something went wrong.