diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2a73383 --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +PROFILES_SERVER_NAME=localhost:8080 + +DEBUG=true + +PROFILES_OIDC_CLIENT_ID=profiles-dev +PROFILES_OIDC_CLIENT_SECRET= +PROFILES_OIDC_LOGOUT_REDIRECT_URI=http://localhost:8080/logout + +LDAP_BIND_DN=uid=yourusername,cn=users,cn=accounts,dc=csh,dc=rit,dc=edu +LDAP_BIND_PASS= + +DATADOG_ENV=local diff --git a/README.md b/README.md index 4581f59..f6d12da 100755 --- a/README.md +++ b/README.md @@ -61,17 +61,32 @@ to SERVER_NAME = os.environ.get('PROFILES_SERVER_NAME', 'localhost:8080') ``` -Reach out to an RTP to get OIDC credentials that will allow you to develop locally behind OIDC auth. +#### OIDC + +Reach out to an RTP to get OIDC credentials that will allow you to develop locally behind OIDC auth. You will need `PROFILES_OIDC_CLIENT_ID` and `PROFILES_OIDC_CLIENT_SECRET` + +#### LDAP ```LDAP_BIND_DN``` is your CSH DN. It is in the following format: ```uid={CSH User Name},cn=users,cn=accounts,dc=csh,dc=rit,dc=edu``` +```LDAP_BIND_PASS``` is your CSH password. + +#### DATADOG - ```LDAP_BIND_PASS``` is your CSH password. +```DATADOG_ENV``` is the env where you are developing, should stay local for local development + +```DATADOG_APP_VERSION``` is the version of your app, when unset defaults to git commit hash If you did everything right, you should be able to run ```python app.py``` and develop locally. +Running with Docker +-------------------- + +Alternatively, you can run profiles using docker or podman compose. You can configure the environment in same way as above, using a `config.py` file, or you can copy the `.env.example` file to `.env` and configure it there. + +The docker-compose file is also set up for automatic redeploying with watch if you run with `podman compose up --watch --build` Code Standards ------------ diff --git a/config.env.py b/config.env.py index 6cbe927..4505441 100644 --- a/config.env.py +++ b/config.env.py @@ -2,12 +2,13 @@ import random import string from os import environ as env +import subprocess # Sentry DSN SENTRY_DSN = env.get("PROFILES_SENTRY_DSN", "") # Flask config -DEBUG = False +DEBUG = os.environ.get("DEBUG", "false").lower() == "true" IP = os.environ.get('PROFILES_IP', 'localhost') PORT = os.environ.get('PROFILES_PORT', 8080) SERVER_NAME = os.environ.get('PROFILES_SERVER_NAME', 'profiles.csh.rit.edu') @@ -25,3 +26,10 @@ LDAP_BIND_DN = env.get("LDAP_BIND_DN", default="cn=profiles,ou=Apps,dc=csh,dc=rit,dc=edu") LDAP_BIND_PASS = env.get("LDAP_BIND_PW", default=None) + +GIT_HASH = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('utf-8').rstrip() + +DATADOG_RUM_CONFIG = { + 'DATADOG_ENV': os.environ.get('DATADOG_ENV', 'local'), + 'DATADOG_APP_VERSION': os.environ.get('DATADOG_APP_VERSION', GIT_HASH), +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..33a0a31 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3" +services: + profiles: + build: . + container_name: profiles + ports: + - "127.0.0.1:8080:8080" + env_file: + - path: .env + required: false + develop: + watch: + - action: sync+restart + path: ./profiles + target: /opt/profiles/profiles + ignore: + - __pycache__ diff --git a/profiles/__init__.py b/profiles/__init__.py index 2289e29..4ae4181 100644 --- a/profiles/__init__.py +++ b/profiles/__init__.py @@ -90,12 +90,15 @@ def home(info=None): @before_request def user(uid=None, info=None): try: - return render_template("profile.html", info=info, member_info=get_member_info(uid)) + return render_template( + "profile.html", info=info, + member_info=get_member_info(uid), **app.config['DATADOG_RUM_CONFIG'] + ) except BadQueryError as bqe: # ldap_get_member() returns a BadQueryError if getting the user's information fails. # Flask already treats a stray BadQueryError as a 404, but actually handling it prevents the traceback # from getting dumped into the log. - return render_template("404.html", message=bqe), 404 + return render_template("404.html", message=bqe, *app.config['DATADOG_RUM_CONFIG']), 404 @app.route("/results", methods=["POST"]) @@ -116,7 +119,8 @@ def search(searched=None, info=None): if len(members) == 1: return redirect("/user/" + members[0].uid, 302) return render_template( - "listing.html", info=info, title="Search Results: " + searched, members=members + "listing.html", info=info, title="Search Results: " + searched, + members=members, *app.config['DATADOG_RUM_CONFIG'] ) @@ -128,7 +132,8 @@ def group(_group=None, info=None): if _group == "eboard": return render_template( - "listing.html", info=info, title=group_desc, members=ldap_get_eboard() + "listing.html", info=info, title=group_desc, + members=ldap_get_eboard(), *app.config['DATADOG_RUM_CONFIG'] ) return render_template( @@ -136,6 +141,7 @@ def group(_group=None, info=None): info=info, title=group_desc, members=_ldap_get_group_members(_group), + *app.config['DATADOG_RUM_CONFIG'] ) @@ -144,7 +150,8 @@ def group(_group=None, info=None): @before_request def year(_year=None, info=None): return render_template( - "listing.html", info=info, title="Year: " + _year, members=ldap_get_year(_year) + "listing.html", info=info, title="Year: " + _year, + members=ldap_get_year(_year), *app.config['DATADOG_RUM_CONFIG'] ) @@ -181,7 +188,7 @@ def image(uid): try: return get_image(uid) except BadQueryError as bqe: - return render_template("404.html", message=bqe), 404 + return render_template("404.html", message=bqe, *app.config['DATADOG_RUM_CONFIG']), 404 @app.route("/clearcache") @@ -214,9 +221,9 @@ def clear_cache(info=None): @app.errorhandler(500) def handle_internal_error(e): if isinstance(e, NotFound): - return render_template("404.html", message=str(e)), 404 + return render_template("404.html", message=str(e), *app.config['DATADOG_RUM_CONFIG']), 404 if isinstance(e.original_exception, BadQueryError): - return render_template("404.html", message=e.original_exception), 404 + return render_template("404.html", message=e.original_exception, *app.config['DATADOG_RUM_CONFIG']), 404 raise e.original_exception diff --git a/profiles/templates/include/head.html b/profiles/templates/include/head.html index 521ba71..4de3859 100644 --- a/profiles/templates/include/head.html +++ b/profiles/templates/include/head.html @@ -28,4 +28,31 @@ + + diff --git a/profiles/utils.py b/profiles/utils.py index 505778f..d026219 100644 --- a/profiles/utils.py +++ b/profiles/utils.py @@ -1,6 +1,5 @@ # Credit to Liam Middlebrook and Ram Zallan # https://github.com/liam-middlebrook/gallery -import subprocess import base64 import datetime @@ -12,6 +11,7 @@ import ldap from profiles import _ldap +import profiles from profiles.ldap import (ldap_get_calendar, ldap_get_member, ldap_get_pronouns, @@ -25,13 +25,11 @@ def before_request(func): @wraps(func) def wrapped_function(*args, **kwargs): - git_revision = subprocess.check_output( - ['git', 'rev-parse', '--short', 'HEAD']).decode('utf-8').rstrip() uuid = str(session["userinfo"].get("sub", "")) uid = str(session["userinfo"].get("preferred_username", "")) user_obj = _ldap.get_member(uid, uid=True) info = { - "git_revision": git_revision, + "git_revision": profiles.app.config['GIT_HASH'], "uuid": uuid, "uid": uid, "user_obj": user_obj,