forked from anitab-org/bridge-in-tech-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: issue19-24 setup and User Registration API
- Loading branch information
1 parent
ba92967
commit c41978c
Showing
51 changed files
with
3,728 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
FLASK_ENVIRONMENT_CONFIG = <dev-or-test-or-prod> | ||
SECRET_KEY = <your-secret-key> | ||
SECURITY_PASSWORD_SALT = <your-security-password-salt> | ||
MAIL_DEFAULT_SENDER = <mail-default-sender> | ||
MAIL_SERVER = <mail-server> | ||
APP_MAIL_USERNAME = <app-mail-username> | ||
APP_MAIL_PASSWORD = <app-mail-password> | ||
MOCK_EMAIL = <True-or-False> | ||
FLASK_APP=run.py | ||
DB_TYPE=postgresql | ||
DB_USERNAME= <db-username> | ||
DB_PASSWORD= <db-password> | ||
DB_ENDPOINT= <db-endpoint> | ||
DB_NAME=bit_schema | ||
DB_TEST_NAME=bit_schema_test |
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,115 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
|
||
# PyCharm project settings | ||
.idea/ | ||
|
||
# vscode | ||
.vscode/ | ||
|
||
*.db | ||
|
||
# aws-eb | ||
.elasticbeanstalk/ |
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 @@ | ||
web: gunicorn run:application |
Empty file.
Empty file.
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,21 @@ | ||
from flask_restx import Api | ||
|
||
api = Api( | ||
title="Bridge In Tech API", | ||
version="1.0", | ||
description="API documentation for the backend of Bridge In Tech. \n \n" | ||
+ "Bridge In Tech is an application inspired by the existing AnitaB.org Mentorship System, " | ||
+ "It encourages organizations to collaborate with the mentors and mentees on mentoring programs. \n \n" | ||
+ "The main repository of the Backend System can be found here: https://github.com/anitab-org/bridge-in-tech-backend \n \n" | ||
+ "The Web client for the Mentorship System can be found here: https://github.com/anitab-org/bridge-in-tech-web \n \n" | ||
+ "For more information about the project here's a link to our wiki guide: https://github.com/anitab-org/bridge-in-tech-backend/wiki" | ||
# doc='/docs/' | ||
) | ||
api.namespaces.clear() | ||
|
||
# Adding namespaces | ||
from app.api.resources.users import users_ns as user_namespace | ||
|
||
api.add_namespace(user_namespace, path="/") | ||
|
||
|
Empty file.
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,37 @@ | ||
from http import HTTPStatus | ||
from typing import Dict | ||
from sqlalchemy import func | ||
from app.database.models.bit_schema.user_extension import UserExtensionModel | ||
from app import messages | ||
|
||
|
||
class UserExtensionDAO: | ||
|
||
"""Data Access Object for Users_Extension functionalities""" | ||
|
||
@staticmethod | ||
def create_user_extension(data): | ||
"""Creates a user_extension instance for a new registered user. | ||
Arguments: | ||
data: A list containing user's id, boolean value of whether or not | ||
the user is representing an organization, as well as their timezone | ||
Returns: | ||
A dictionary containing "message" which indicates whether or not the user_exension was created successfully and "code" for the HTTP response code. | ||
""" | ||
|
||
user_id = data["user_id"] | ||
is_organization_rep = data["is_organization_rep"] | ||
timezone = data["timezone"] | ||
|
||
user_extension = UserExtensionModel(user_id, is_organization_rep, timezone) | ||
|
||
user_extension.save_to_db() | ||
|
||
response = { | ||
"message": f"{messages.USER_WAS_CREATED_SUCCESSFULLY}", | ||
"code": f"{HTTPStatus.CREATED}", | ||
} | ||
|
||
return response |
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,24 @@ | ||
from flask_jwt_extended import JWTManager | ||
from http import HTTPStatus | ||
from app import messages | ||
from app.api.bit_extension import api | ||
|
||
jwt = JWTManager() | ||
|
||
# This is needed for the error handlers to work with flask-restplus | ||
jwt._set_error_handler_callbacks(api) | ||
|
||
|
||
@jwt.expired_token_loader | ||
def my_expired_token_callback(): | ||
return messages.TOKEN_HAS_EXPIRED, HTTPStatus.UNAUTHORIZED | ||
|
||
|
||
@jwt.invalid_token_loader | ||
def my_invalid_token_callback(error_message): | ||
return messages.TOKEN_IS_INVALID, HTTPStatus.UNAUTHORIZED | ||
|
||
|
||
@jwt.unauthorized_loader | ||
def my_unauthorized_request_callback(error_message): | ||
return messages.AUTHORISATION_TOKEN_IS_MISSING, HTTPStatus.UNAUTHORIZED |
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,3 @@ | ||
from flask_mail import Mail | ||
|
||
mail = Mail() |
Empty file.
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,24 @@ | ||
from flask_restx import fields, Model | ||
from app.utils.bitschema_utils import Timezone | ||
|
||
def add_models_to_namespace(api_namespace): | ||
api_namespace.models[register_user_api_model.name] = register_user_api_model | ||
|
||
register_user_api_model = Model( | ||
"User registration model", | ||
{ | ||
"name": fields.String(required=True, description="User name"), | ||
"username": fields.String(required=True, description="User username"), | ||
"password": fields.String(required=True, description="User password"), | ||
"email": fields.String(required=True, description="User email"), | ||
"terms_and_conditions_checked": fields.Boolean( | ||
required=True, description="User check Terms and Conditions value" | ||
), | ||
"need_mentoring": fields.Boolean( | ||
required=False, description="User need mentoring indication" | ||
), | ||
"available_to_mentor": fields.Boolean( | ||
required=False, description="User availability to mentor indication" | ||
), | ||
}, | ||
) |
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,58 @@ | ||
from flask import jsonify | ||
import requests | ||
# from requests.exceptions import HTTPError | ||
from flask import json | ||
|
||
from werkzeug.exceptions import HTTPException | ||
import logging | ||
|
||
# set base url | ||
|
||
# for ms-api local server | ||
BASE_MS_API_URL = "http://127.0.0.1:4000" | ||
|
||
# for ms-api heroku server | ||
# BASE_MS_API_URL = "https://bridge-in-tech-ms-test.herokuapp.com" | ||
|
||
# @application.errorhandler(HTTPException) | ||
# def handle_exception(e): | ||
# """Return JSON instead of HTML for HTTP errors.""" | ||
# # start with the correct headers and status code from the error | ||
# response = e.get_response() | ||
# # replace the body with JSON | ||
# response.data = json.dumps({ | ||
# "code": e.code, | ||
# "name": e.name, | ||
# "description": e.description, | ||
# }) | ||
# response.content_type = "application/json" | ||
# return response | ||
|
||
# create instance | ||
def post_request(request_url, data): | ||
response = None, | ||
try: | ||
|
||
response_raw = requests.post( | ||
request_url, | ||
json = data, | ||
headers = {"Accept": "application/json"} | ||
) | ||
response_raw.status_code = 201 | ||
response_raw.encoding = "utf-8" | ||
response = response_raw.json() | ||
|
||
except HTTPException as e: | ||
response = e.get_response() | ||
response.data = json.dumps({ | ||
"code": e.code, | ||
"name": e.name, | ||
"description": e.description, | ||
}) | ||
response.content_type = "application/json" | ||
|
||
print(f"{response}") | ||
return response | ||
|
||
|
||
|
Empty file.
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,47 @@ | ||
from flask import request | ||
from flask_restx import Resource, marshal, Namespace | ||
from app.api.ms_api_utils import * | ||
from app.api.dao.user_extension import UserExtensionDAO | ||
from flask import json | ||
from http import HTTPStatus | ||
from app import messages | ||
from app.api.models.user_extension import * | ||
|
||
users_ns = Namespace("Users", description="Operations related to users") | ||
add_models_to_namespace(users_ns) | ||
|
||
DAO = UserExtensionDAO() | ||
|
||
@users_ns.route("register") | ||
class UserRegister(Resource): | ||
@classmethod | ||
@users_ns.doc("create_user") | ||
@users_ns.response(HTTPStatus.CREATED, "%s" % messages.USER_WAS_CREATED_SUCCESSFULLY) | ||
@users_ns.response(HTTPStatus.BAD_REQUEST, "%s" % messages.PASSWORD_INPUT_BY_USER_HAS_INVALID_LENGTH) | ||
@users_ns.response( | ||
HTTPStatus.CONFLICT, | ||
"%s\n%s\n%s" | ||
% ( | ||
messages.USER_USES_A_USERNAME_THAT_ALREADY_EXISTS, | ||
messages.USER_USES_AN_EMAIL_ID_THAT_ALREADY_EXISTS, | ||
), | ||
) | ||
@users_ns.response(HTTPStatus.INTERNAL_SERVER_ERROR, "%s" % messages.INTERNAL_SERVER_ERROR) | ||
@users_ns.expect(register_user_api_model, validate=True) | ||
|
||
def post(cls): | ||
""" | ||
Creates a new user. | ||
The endpoint accepts user input related to Mentorship System API (name, username, password, email, | ||
terms_and_conditions_checked(true/false), need_mentoring(true/false), | ||
available_to_mentor(true/false)) and Bridge In Tech API (is_organization_rep and timezone). | ||
A success message is displayed and verification email is sent to the user's email ID. | ||
""" | ||
|
||
data = request.json | ||
|
||
# send POST /register request to MS API and return response | ||
return post_request(f"{BASE_MS_API_URL}/register", data) | ||
|
||
|
Empty file.
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,22 @@ | ||
from app import messages | ||
from app.utils.validation_utils import validate_length, get_stripped_string | ||
|
||
COMMENT_MAX_LENGTH = 400 | ||
|
||
|
||
def validate_task_comment_request_data(data): | ||
if "comment" not in data: | ||
return messages.COMMENT_FIELD_IS_MISSING | ||
|
||
comment = data["comment"] | ||
|
||
if not isinstance(comment, str): | ||
return messages.COMMENT_NOT_IN_STRING_FORMAT | ||
|
||
is_valid = validate_length( | ||
len(get_stripped_string(data["comment"])), 0, COMMENT_MAX_LENGTH, "comment" | ||
) | ||
if not is_valid[0]: | ||
return is_valid[1] | ||
|
||
return {} |
Oops, something went wrong.