Skip to content

Update sample apps for Python SDK v5 #59

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

Merged
merged 31 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
152b941
Update home page on sample app for 5.0
tribble Jul 16, 2024
320abf0
Updates and fixes
tribble Jul 16, 2024
480d240
Add views for user and group details
tribble Jul 16, 2024
e0e094d
API tweaks
tribble Jul 16, 2024
c92e84b
Add guards to satisfy typing
tribble Jul 16, 2024
358d7ab
Add events page and fix up users
tribble Aug 1, 2024
a78fcfc
Make logo go back to home page
tribble Aug 1, 2024
e4c08eb
Handle no more events
tribble Aug 1, 2024
6b32200
Update sample for 5.0
tribble Aug 2, 2024
25f6754
Simplify type validation
tribble Aug 2, 2024
2f0a918
Update version requirement
tribble Aug 2, 2024
7994681
Update version requirement
tribble Aug 2, 2024
1328d22
Update audit logs app for 5.0
tribble Aug 2, 2024
a93126f
Update magic link app to 5.0
tribble Aug 3, 2024
635152e
Update mfa app for 5.0
tribble Aug 5, 2024
ceb7141
Update sso app for 5.0
tribble Aug 6, 2024
7979026
Remove unused imports
tribble Aug 7, 2024
3d99705
Minor change to admin portal app import
tribble Aug 8, 2024
680846c
Update directory sync flask app for the new client init and kwargs
tribble Aug 12, 2024
2c4ec79
Update for client changes
tribble Aug 12, 2024
1c1f24b
Add debug base url to dsync app
tribble Aug 12, 2024
a648ffe
Update for new client
tribble Aug 12, 2024
2c793de
Update for new client
tribble Aug 12, 2024
fbe32ce
Update for new client
tribble Aug 12, 2024
738f955
Update for new client
tribble Aug 12, 2024
29d6a8b
greater than or equal to 5.0
tribble Aug 12, 2024
ee10c0d
Fix workos version
tribble Aug 12, 2024
143e051
Greater or equal to 5.0
tribble Aug 12, 2024
4bb9401
Update event verification with new param name
tribble Aug 14, 2024
70fb316
Slight tweak to domain creation
tribble Aug 14, 2024
cdd2936
Replace DEBUG global with an env variable to set the base api url
tribble Aug 14, 2024
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
45 changes: 32 additions & 13 deletions python-flask-admin-portal-example/app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from email.mime import base
import os

from flask import Flask, redirect, render_template, request, url_for
from flask import Flask, redirect, render_template, request
import workos
from workos import client as workos_client
from workos import portal
from flask_lucide import Lucide
from workos.types import DomainDataInput


# Flask Setup
Expand All @@ -13,9 +12,12 @@
lucide = Lucide(app)

# WorkOS Setup
workos.api_key = os.getenv("WORKOS_API_KEY")
workos.project_id = os.getenv("WORKOS_CLIENT_ID")
workos.base_api_url = "http://localhost:7000/" if DEBUG else workos.base_api_url
base_api_url = "http://localhost:7000/" if DEBUG else None
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels kind of odd to me for a public example. I wonder if we should just use the WORKOS_BASE_URL environment variable here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This is a simple change I can make to all of the sample apps.

workos_client = workos.WorkOSClient(
api_key=os.getenv("WORKOS_API_KEY"),
client_id=os.getenv("WORKOS_CLIENT_ID"),
base_url=base_api_url,
)


@app.route("/")
Expand All @@ -32,21 +34,38 @@ def provision_enterprise():

# Check if a matching domain already exists and set global org_id if there is a match
orgs = workos_client.organizations.list_organizations(domains=organization_domains)
if len(orgs["data"]) > 0:
org_id = orgs["data"][0]["id"]
if len(orgs.data) > 0:
org_id = orgs.data[0].id

# Otherwise create a new Organization and set the global org_id
else:
domain_data = list(
map(
lambda domain: DomainDataInput({"domain": domain, "state": "verified"}),
organization_domains,
)
)

organization = workos_client.organizations.create_organization(
{"name": organization_name, "domains": organization_domains}
name=organization_name,
domain_data=domain_data,
)
org_id = organization["id"]
org_id = organization.id

return render_template("org_logged_in.html")


@app.route("/launch_admin_portal", methods=["GET", "POST"])
def launch_admin_portal():
intent = request.args.get("intent")
portal_link = workos_client.portal.generate_link(organization=org_id, intent=intent)
return redirect(portal_link["link"])

if intent is None:
return "Missing intent parameter", 400

if not intent in tuple(("audit_logs", "dsync", "log_streams", "sso")):
return "Invalid intent parameter", 400

portal_link = workos_client.portal.generate_link(
organization_id=org_id, intent=intent
)
return redirect(portal_link.link)
4 changes: 2 additions & 2 deletions python-flask-admin-portal-example/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
certifi==2021.5.30
charset-normalizer==2.0.6
click==8.0.1
Flask==2.0.1
Flask==2.0.3
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different examples used different flask versions. I set them all to the same version.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we can't bump to the latest Flask version? Also fine with keeping this out of scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason I didn't bump up to latest version was to limit the scope of changes as I swept through and updated the sample apps. Basically, time savings for me in case bumping up to latest Flask triggered other code or dependency changes.

idna==3.2
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
requests==2.26.0
urllib3==1.26.7
Werkzeug==2.0.1
workos>=1.23.3
workos>=5.0.0
python-dotenv
flask-lucide==0.2.0
112 changes: 63 additions & 49 deletions python-flask-audit-logs-example/app.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import json
import os
from urllib.parse import urlparse, parse_qs
from flask import Flask, session, redirect, render_template, request, url_for
from flask import Flask, session, redirect, render_template, request
import workos
from datetime import datetime, timedelta
from audit_log_events import (
user_organization_set,
)
from workos.audit_logs import AuditLogEvent
from flask_lucide import Lucide


Expand All @@ -19,9 +19,12 @@


# WorkOS Setup
workos.api_key = os.getenv("WORKOS_API_KEY")
workos.project_id = os.getenv("WORKOS_CLIENT_ID")
workos.base_api_url = "http://localhost:7000/" if DEBUG else workos.base_api_url
base_api_url = "http://localhost:7000/" if DEBUG else None
workos_client = workos.WorkOSClient(
api_key=os.getenv("WORKOS_API_KEY"),
client_id=os.getenv("WORKOS_CLIENT_ID"),
base_url=base_api_url,
)


def to_pretty_json(value):
Expand All @@ -34,14 +37,14 @@ def to_pretty_json(value):
@app.route("/", methods=["POST", "GET"])
def index():
try:
link = workos.client.portal.generate_link(
organization=session["organization_id"], intent="audit_logs"
link = workos_client.portal.generate_link(
organization_id=session["organization_id"], intent="audit_logs"
)
today = datetime.today()
last_month = today - timedelta(days=30)
return render_template(
"send_events.html",
link=link["link"],
link=link.link,
organization_id=session["organization_id"],
org_name=session["organization_name"],
last_month_iso=last_month.isoformat(),
Expand All @@ -50,29 +53,29 @@ def index():
except KeyError:
before = request.args.get("before")
after = request.args.get("after")
organizations = workos.client.organizations.list_organizations(
before=before, after=after, limit=5, order=None
organizations = workos_client.organizations.list_organizations(
before=before, after=after, limit=5, order="desc"
)
before = organizations["listMetadata"]["before"]
after = organizations["listMetadata"]["after"]
before = organizations.list_metadata.before
after = organizations.list_metadata.after
return render_template(
"login.html",
organizations=organizations["data"],
organizations=organizations.data,
before=before,
after=after,
)


@app.route("/set_org", methods=["POST", "GET"])
def set_org():
organization_id = request.args.get("id")
organization_id = request.args.get("id") or request.form["organization_id"]

session["organization_id"] = organization_id
organization_set = workos.client.audit_logs.create_event(
organization_id, user_organization_set
workos_client.audit_logs.create_event(
organization_id=organization_id, event=user_organization_set
)
org = workos.client.organizations.get_organization(organization_id)
org_name = org["name"]
session["organization_name"] = org_name
org = workos_client.organizations.get_organization(organization_id)
session["organization_name"] = org.name
return redirect("/")


Expand All @@ -87,28 +90,32 @@ def send_event():
)
organization_id = session["organization_id"]

event = {
"action": "user.organization_deleted",
"version": int(event_version),
"occurred_at": datetime.now().isoformat(),
"actor": {
"type": actor_type,
"name": actor_name,
"id": "user_01GBNJC3MX9ZZJW1FSTF4C5938",
},
"targets": [
{
"type": target_type,
"name": target_name,
"id": "team_01GBNJD4MKHVKJGEWK42JNMBGS",
event = AuditLogEvent(
{
"action": "user.organization_deleted",
"version": int(event_version),
"occurred_at": datetime.now().isoformat(),
"actor": {
"type": actor_type,
"name": actor_name,
"id": "user_01GBNJC3MX9ZZJW1FSTF4C5938",
},
],
"context": {
"location": "123.123.123.123",
"user_agent": "Chrome/104.0.0.0",
},
}
organization_set = workos.client.audit_logs.create_event(organization_id, event)
"targets": [
{
"type": target_type,
"name": target_name,
"id": "team_01GBNJD4MKHVKJGEWK42JNMBGS",
},
],
"context": {
"location": "123.123.123.123",
"user_agent": "Chrome/104.0.0.0",
},
}
)
organization_set = workos_client.audit_logs.create_event(
organization_id=organization_id, event=event
)
return redirect("/")


Expand Down Expand Up @@ -147,33 +154,40 @@ def get_events():

try:

create_export_response = workos.client.audit_logs.create_export(
organization=organization_id,
create_export_response = workos_client.audit_logs.create_export(
organization_id=organization_id,
range_start=request.form["range-start"],
range_end=request.form["range-end"],
actions=actions,
actors=actors,
actor_names=actors,
targets=targets,
)
session["export_id"] = create_export_response.to_dict()["id"]
session["export_id"] = create_export_response.id

return redirect("export_events")
except Exception as e:
print(str(e))
return redirect("/")
if event_type == "access_csv":
export_id = session["export_id"]
fetch_export_response = workos.client.audit_logs.get_export(export_id)
return redirect(fetch_export_response.to_dict()["url"])
fetch_export_response = workos_client.audit_logs.get_export(export_id)
if fetch_export_response.url is None:
return redirect("/")

return redirect(fetch_export_response.url)


@app.route("/events", methods=["GET"])
def events():
link = workos.client.portal.generate_link(
organization=session["organization_id"], intent=request.args.get("intent")
intent = request.args.get("intent")
if not intent == "audit_logs":
return redirect("/")

link = workos_client.portal.generate_link(
organization_id=session["organization_id"], intent=intent
)

return redirect(link["link"])
return redirect(link.link)


@app.route("/logout")
Expand Down
37 changes: 20 additions & 17 deletions python-flask-audit-logs-example/audit_log_events.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from datetime import datetime
from workos.audit_logs import AuditLogEvent

user_organization_set = {
"action": "user.organization_set",
"occurred_at": datetime.now().isoformat(),
"actor": {
"type": "user",
"id": "user_01GBNJC3MX9ZZJW1FSTF4C5938",
},
"targets": [
{
"type": "team",
"id": "team_01GBNJD4MKHVKJGEWK42JNMBGS",
user_organization_set = AuditLogEvent(
{
"action": "user.organization_set",
"occurred_at": datetime.now().isoformat(),
"actor": {
"type": "user",
"id": "user_01GBNJC3MX9ZZJW1FSTF4C5938",
},
],
"context": {
"location": "123.123.123.123",
"user_agent": "Chrome/104.0.0.0",
},
}
"targets": [
{
"type": "organization",
"id": "team_01GBNJD4MKHVKJGEWK42JNMBGS",
},
],
"context": {
"location": "123.123.123.123",
"user_agent": "Chrome/104.0.0.0",
},
}
)
5 changes: 3 additions & 2 deletions python-flask-audit-logs-example/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Flask==2.0.3
Jinja2==3.1.1
workos>=1.23.3
workos>=5.0.0
python-dotenv
flask-lucide==0.2.0
flask-lucide==0.2.0
Werkzeug==2.0.1
Loading
Loading