Skip to content

Commit

Permalink
Merge pull request #4 from silentworks/09-30-Update_supabase_instanti…
Browse files Browse the repository at this point in the history
…ation_to_use_flask_g_and_localproxy

Update supabase instantiation to use flask g and localproxy
  • Loading branch information
silentworks authored Sep 30, 2023
2 parents 4c23471 + 0bf41a2 commit 2c9a23b
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 143 deletions.
7 changes: 6 additions & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flask import Flask, abort, render_template
from flask import Flask, g, render_template
from app.supabase import (
session_context_processor,
get_profile_by_slug,
Expand All @@ -19,6 +19,11 @@
app.register_blueprint(notes)


@app.teardown_appcontext
def close_supabase(e=None):
g.pop("supabase", None)


@app.route("/")
@login_required
@password_update_required
Expand Down
21 changes: 13 additions & 8 deletions app/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,27 @@ def signup():
email = form.email.data
password = form.password.data

user = supabase.auth.sign_up(credentials={"email": email, "password": password})
try:
user = supabase.auth.sign_up(
credentials={"email": email, "password": password}
)

if user:
return redirect(url_for("home"))
else:
flash("User registration failed!", "error")
if user:
flash(
"Please check your email for a magic link to log into the website.",
"info",
)
else:
flash("User registration failed!", "error")
except AuthApiError as message:
flash(message, "error")

return render_template("auth/signup.html", form=form)


@auth.route("/signout", methods=["POST"])
def signout():
supabase.auth.sign_out()
# TODO: remove workaround once
# https://github.com/supabase-community/supabase-py/pull/560 is merged and released
# supabase.postgrest.auth(token=supabase_key)
return redirect(url_for("auth.signin"))


Expand Down
3 changes: 0 additions & 3 deletions app/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ def decorated(*args, **kwargs):
sess: Union[Session, None] = None
try:
sess = supabase.auth.get_session()
# TODO: remove workaround once
# https://github.com/supabase-community/supabase-py/pull/560 is merged and released
# supabase.postgrest.auth(token=sess.access_token)
except AuthApiError as exception:
err = exception.to_dict()
if err.get("message") == "Invalid Refresh Token: Already Used":
Expand Down
57 changes: 33 additions & 24 deletions app/notes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import base64
import io
import requests
from flask import Blueprint, flash, redirect, render_template, request, url_for
from PIL import Image, ImageOps
from urllib.request import urlopen
from postgrest.exceptions import APIError
from app.forms import NoteForm
from app.supabase import (
Expand Down Expand Up @@ -34,23 +34,27 @@ def home():
def new():
profile = get_profile_by_user()
form = NoteForm(data=profile)
path = None
if form.validate_on_submit():
title = form.title.data
content = form.content.data
is_public = form.is_public.data
featured_image = form.featured_image.name
image = request.files[featured_image]
image_stream = io.BytesIO()
image.save(image_stream)
path = f"{profile['id']}/{random_choice().lower()}_fi.png"
# check if image is set
if image:
image_stream = io.BytesIO()
image.save(image_stream)
path = f"{profile['id']}/{random_choice().lower()}_fi.png"

try:
# Upload file
r = supabase.storage.from_("featured_image").upload(
path=path,
file=image_stream.getvalue(),
file_options={"content-type": image.content_type},
)
if path is not None:
r = supabase.storage.from_("featured_image").upload(
path=path,
file=image_stream.getvalue(),
file_options={"content-type": image.content_type},
)

# Save to database
res = (
Expand Down Expand Up @@ -89,9 +93,10 @@ def edit(note_id):
profile = get_profile_by_user()
note = get_note_by_user_and_id(note_id)
form = NoteForm(data=note)
image = None
if note["featured_image"] is not None:
# A Supabase PRO plan is required to use image transforms
preview_image = None
path = note["featured_image"]
if path is not None:
# A Supabase PRO plan is required to use the image transform below
# r = supabase.storage.from_("featured_image").get_public_url(
# note["featured_image"],
# options={"transform": {"width": 200}},
Expand All @@ -105,28 +110,28 @@ def edit(note_id):
r = supabase.storage.from_("featured_image").get_public_url(
note["featured_image"]
)
url_to_stream = urlopen(r)
img = Image.open(url_to_stream)
img = ImageOps.contain(img, (200, 200))
image_stream = io.BytesIO()
img.save(image_stream, format="png")
image = f"data:image/png;base64, {base64.b64encode(image_stream.getvalue()).decode('utf-8')}"
else:
path = note["featured_image"]
response = requests.get(r, stream=True)
content_size = response.headers.get("Content-length")
if content_size != "0":
img = Image.open(response.raw)
img = ImageOps.contain(img, (200, 200))
image_stream = io.BytesIO()
img.save(image_stream, format="png")
preview_image = f"data:image/png;base64, {base64.b64encode(image_stream.getvalue()).decode('utf-8')}"

if form.validate_on_submit():
title = form.title.data
content = form.content.data
is_public = form.is_public.data
featured_image = form.featured_image.name
if featured_image is not None:
image = request.files[featured_image]
image = request.files[featured_image]
if image:
image_stream = io.BytesIO()
image.save(image_stream)
path = f"{profile['id']}/{random_choice().lower()}_fi.png"

try:
if featured_image is not None:
if image:
# Upload file
r = supabase.storage.from_("featured_image").upload(
path=path,
Expand Down Expand Up @@ -162,5 +167,9 @@ def edit(note_id):
flash(exception.message, "error")

return render_template(
"notes/edit.html", profile=profile, form=form, note=note, image=image
"notes/edit.html",
profile=profile,
form=form,
note=note,
preview_image=preview_image,
)
23 changes: 15 additions & 8 deletions app/supabase.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import os
from flask import g
from werkzeug.local import LocalProxy
from supabase.client import create_client, Client
from supabase.lib.client_options import ClientOptions
from app.flask_storage import FlaskSessionStorage
Expand All @@ -9,13 +11,16 @@
url = os.environ.get("SUPABASE_URL", "")
key = os.environ.get("SUPABASE_KEY", "")

supabase: Client = create_client(
url,
key,
options=ClientOptions(
storage=FlaskSessionStorage(),
),
)

def get_supabase() -> Client:
if "supabase" not in g:
g.supabase: Client = create_client(
url, key, options=ClientOptions(storage=FlaskSessionStorage())
)
return g.supabase


supabase: Client = LocalProxy(get_supabase)


def session_context_processor():
Expand Down Expand Up @@ -64,7 +69,9 @@ def get_notes(user_or_slug: Union[User, str]):
# get profile and profile_info
notes = {}
try:
query = supabase.table("notes").select("*")
query = (
supabase.table("notes").select("*").order(column="created_at", desc=True)
)

if hasattr(user_or_slug, "id"):
query = query.match({"author_id": user_or_slug.id})
Expand Down
14 changes: 7 additions & 7 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ email-validator = "^2.0.0.post2"
poetry-dotenv-plugin = "^0.2.0"
gunicorn = "^21.2.0"
pillow = "^10.0.1"
requests = "^2.31.0"

[tool.flake8]
ignore = ["F401", "E402"]
Expand Down
Loading

0 comments on commit 2c9a23b

Please sign in to comment.