From dd4ea9402176196da15377f809a0c87cc54b4021 Mon Sep 17 00:00:00 2001
From: Scoder12 <34356756+Scoder12@users.noreply.github.com>
Date: Mon, 27 Jul 2020 17:12:47 -0700
Subject: [PATCH 1/5] Copy maqpi code
---
examples/maqpi/manual_auth.py | 16 ++++++++
src/replit/maqpi/__init__.py | 20 +++++++++
src/replit/maqpi/app.py | 77 +++++++++++++++++++++++++++++++++++
src/replit/maqpi/files.py | 65 +++++++++++++++++++++++++++++
src/replit/maqpi/html.py | 43 +++++++++++++++++++
src/replit/maqpi/utils.py | 20 +++++++++
6 files changed, 241 insertions(+)
create mode 100644 examples/maqpi/manual_auth.py
create mode 100644 src/replit/maqpi/__init__.py
create mode 100644 src/replit/maqpi/app.py
create mode 100644 src/replit/maqpi/files.py
create mode 100644 src/replit/maqpi/html.py
create mode 100644 src/replit/maqpi/utils.py
diff --git a/examples/maqpi/manual_auth.py b/examples/maqpi/manual_auth.py
new file mode 100644
index 0000000..2cdaecf
--- /dev/null
+++ b/examples/maqpi/manual_auth.py
@@ -0,0 +1,16 @@
+"""A basic example of repl auth."""
+import simple
+
+app = simple.App("app")
+
+
+@app.route("/")
+def index():
+ if simple.signed_in:
+ return "Hello " + simple.auth.name
+ else:
+ return simple.signin() # optionally: simple.sigin(title="My title")
+
+
+if __name__ == "__main__":
+ app.run()
diff --git a/src/replit/maqpi/__init__.py b/src/replit/maqpi/__init__.py
new file mode 100644
index 0000000..a6f61ce
--- /dev/null
+++ b/src/replit/maqpi/__init__.py
@@ -0,0 +1,20 @@
+"""Make apps quickly in python."""
+import os
+
+import flask
+from werkzeug.local import LocalProxy
+
+from . import html
+from .app import App
+from .html import Page, Paragraph
+from .utils import sign_in_snippet, signin
+
+# TODO: import new db package package name
+
+db = ReplitDb(os.environ["REPLIT_DB_URL"])
+auth = LocalProxy(lambda: flask.request.auth)
+signed_in = LocalProxy(lambda: flask.request.signed_in)
+
+# TODO: signinwall(exclude=['/a', '/b'])
+# TODO: @need_signin
+# TODO: Param checking with @needs_params
diff --git a/src/replit/maqpi/app.py b/src/replit/maqpi/app.py
new file mode 100644
index 0000000..f74aca0
--- /dev/null
+++ b/src/replit/maqpi/app.py
@@ -0,0 +1,77 @@
+"""Core of maqpi."""
+from dataclasses import dataclass
+from typing import Any
+
+import flask
+
+
+@dataclass
+class ReplitAuthContext:
+ """A dataclass defining a Repl Auth state."""
+
+ user_id: int
+ name: str
+ roles: str
+
+ @classmethod
+ def from_headers(cls, headers: dict):
+ """Initialize an instance using the Replit magic headers.
+
+ Args:
+ headers (dict): A dictionary of headers received
+
+ Returns:
+ [type]: An initialized class instance
+ """
+ return cls(
+ user_id=headers.get("X-Replit-User-Id"),
+ name=headers.get("X-Replit-User-Name"),
+ roles=headers.get("X-Replit-User-Roles"),
+ )
+
+ @property
+ def signed_in(self) -> bool:
+ """Return whether or not the authentication is activated."""
+ return self.name != ""
+
+
+class Request(flask.Request):
+ """Represents a client request."""
+
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
+ """Initialize request and run update_auth."""
+ super().__init__(*args, **kwargs)
+ self.update_auth()
+
+ def update_auth(self) -> None:
+ """Update the auth property to be a ReplitAuthContext."""
+ self.auth = ReplitAuthContext.from_headers(self.headers)
+
+ @property
+ def signed_in(self) -> bool:
+ """Return whether or not the authentication is activated."""
+ return self.auth.signed_in
+
+
+class App(flask.Flask):
+ """Represents a web application."""
+
+ request_class = Request
+
+ def all_pages_sign_in(self) -> None:
+ """Require sign-in on all pages."""
+ raise NotImplementedError()
+
+ def _run(self, *args: Any, **kwargs: Any) -> Any:
+ """Interface with the underlying flask instance's run function."""
+ return super().run(*args, **kwargs)
+
+ def run(self, port: int = 8080, localhost: bool = False) -> None:
+ """Run the app.
+
+ Args:
+ port (int): The port to run the app on. Defaults to 8080.
+ localhost (bool): Whether to run the app without exposing it on all
+ interfaces. Defaults to False.
+ """
+ super().run(host="localhost" if localhost else "0.0.0.0", port=port)
diff --git a/src/replit/maqpi/files.py b/src/replit/maqpi/files.py
new file mode 100644
index 0000000..b4a55ea
--- /dev/null
+++ b/src/replit/maqpi/files.py
@@ -0,0 +1,65 @@
+"""Utitilities for interacting with static files."""
+import flask
+
+
+class FileCache:
+ """A simple cache for files."""
+
+ def __init__(self) -> None:
+ self.data = {}
+
+ def add_to_cache(self, filename: str, content: str) -> None:
+ """Add a filename to the cache.
+
+ Args:
+ filename (str): The filename to add.
+ content (str): The content to add to the cache.
+ """
+ self.data[filename] = content
+
+ def has(self, filename: str) -> bool:
+ """Whether the cache has a certain filename.
+
+ Args:
+ filename (str): The filename to check for.
+
+ Returns:
+ bool: Whether the cache has filename.
+ """
+ return filename in self.data
+
+ def invalidate(self, filename: str) -> None:
+ """Remove a filename from the cache.
+
+ Args:
+ filename (str): The filename to remove.
+ """
+ try:
+ self.data.pop(filename)
+ except KeyError:
+ pass
+
+ def flush(self) -> None:
+ """Remove all values from the cache."""
+ self.data = {}
+
+
+cache = FileCache()
+
+
+class File(flask.Response):
+ """Represents a static file."""
+
+ def __init__(self, filename: str, no_cache: bool = False) -> None:
+ self.filename = str(filename)
+ self.no_cache = no_cache
+
+ # load file
+ if filename not in cache:
+ with open(filename, "r") as f:
+ self.content = f.read()
+
+ if not no_cache:
+ cache.add_to_cache(filename, self.content)
+
+ super().__init__(self.content)
diff --git a/src/replit/maqpi/html.py b/src/replit/maqpi/html.py
new file mode 100644
index 0000000..f2ea5b6
--- /dev/null
+++ b/src/replit/maqpi/html.py
@@ -0,0 +1,43 @@
+"""Class-representations for HTML elements."""
+from abc import ABC
+from dataclasses import dataclass
+
+import flask
+
+
+class HTMLElement(ABC):
+ """Base class for an HTML element."""
+
+ pass
+
+
+@dataclass
+class Paragraph:
+ """Represents a Paragraph (p) tag."""
+
+ content: str
+
+ def __str__(self) -> str:
+ return f"
{self.content}
"
+
+
+class Page(flask.Response):
+ """Represents an HTML page."""
+
+ def __init__(self, title: str = None, head: str = "", body: str = "") -> None:
+ self.title = title
+ self.head = head
+ self.body = body
+
+ title_html = f"{self.title}\n " if self.title else ""
+ super().__init__(
+ f"""
+
+
+ {title_html}{self.head}
+
+
+ {self.body}
+
+"""
+ )
diff --git a/src/replit/maqpi/utils.py b/src/replit/maqpi/utils.py
new file mode 100644
index 0000000..7935a39
--- /dev/null
+++ b/src/replit/maqpi/utils.py
@@ -0,0 +1,20 @@
+"""Utitilities to make development easier."""
+from .html import Page
+
+
+sign_in_snippet = (
+ ''
+)
+
+
+def signin(title: str = "Please Sign In") -> Page:
+ """Return a sign-in page.
+
+ Args:
+ title (str): The title of the sign in page. Defaults to "Please Sign In".
+
+ Returns:
+ Page: The sign-in page.
+ """
+ return Page(title=title, body=sign_in_snippet)
From b202b5729da6f643fc8d3442dc8a4b4841adcd0b Mon Sep 17 00:00:00 2001
From: Scoder12 <34356756+Scoder12@users.noreply.github.com>
Date: Mon, 27 Jul 2020 17:20:37 -0700
Subject: [PATCH 2/5] Ignore import but unused in maqpi init
---
.flake8 | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.flake8 b/.flake8
index 46d4260..ee5a677 100644
--- a/.flake8
+++ b/.flake8
@@ -1,7 +1,9 @@
[flake8]
select = ANN,B,B9,BLK,C,D,DAR,E,F,I,S,W
ignore = E203,W503,ANN101,ANN102,S322
-per-file-ignores = src/replit/__init__.py:F401
+per-file-ignores =
+ src/replit/__init__.py:F401
+ src/replit/maqpi/__init__.py:F401
max-line-length = 88
application-import-names = vidgen,tests
import-order-style = google
From d9dfb5a561369673837d02bb4756351fc0ebeb51 Mon Sep 17 00:00:00 2001
From: Scoder12 <34356756+Scoder12@users.noreply.github.com>
Date: Mon, 27 Jul 2020 17:21:01 -0700
Subject: [PATCH 3/5] Add flask dependency for maqpi
---
poetry.lock | 57 +++++++++++++++++++++++++++++++++++++++++++++++---
pyproject.toml | 1 +
2 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index 87282bc..81ad6ea 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -91,7 +91,7 @@ python-versions = "*"
version = "3.0.4"
[[package]]
-category = "dev"
+category = "main"
description = "Composable command line interface toolkit"
name = "click"
optional = false
@@ -218,6 +218,25 @@ version = "1.0.2"
[package.dependencies]
flake8 = "*"
+[[package]]
+category = "main"
+description = "A simple framework for building complex web applications."
+name = "flask"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+version = "1.1.2"
+
+[package.dependencies]
+Jinja2 = ">=2.10.1"
+Werkzeug = ">=0.15"
+click = ">=5.1"
+itsdangerous = ">=0.24"
+
+[package.extras]
+dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+dotenv = ["python-dotenv"]
+
[[package]]
category = "dev"
description = "Git Object Database"
@@ -257,7 +276,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.2.0"
[[package]]
-category = "dev"
+category = "main"
+description = "Various helpers to pass data to untrusted environments and back."
+name = "itsdangerous"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+version = "1.1.0"
+
+[[package]]
+category = "main"
description = "A very fast and expressive template engine."
name = "jinja2"
optional = false
@@ -271,7 +298,7 @@ MarkupSafe = ">=0.23"
i18n = ["Babel (>=0.8)"]
[[package]]
-category = "dev"
+category = "main"
description = "Safely add untrusted strings to HTML/XML markup."
name = "markupsafe"
optional = false
@@ -602,6 +629,18 @@ brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
+[[package]]
+category = "main"
+description = "The comprehensive WSGI web application library."
+name = "werkzeug"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+version = "1.0.1"
+
+[package.extras]
+dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
+watchdog = ["watchdog"]
+
[metadata]
content-hash = "7388d8240a2817695e502fb845922da8df699d77d143693ffe3285eca1df3495"
python-versions = "^3.8"
@@ -685,6 +724,10 @@ flake8-polyfill = [
{file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"},
{file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"},
]
+flask = [
+ {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
+ {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
+]
gitdb = [
{file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"},
{file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"},
@@ -701,6 +744,10 @@ imagesize = [
{file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"},
{file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"},
]
+itsdangerous = [
+ {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
+ {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
+]
jinja2 = [
{file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
{file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
@@ -908,3 +955,7 @@ urllib3 = [
{file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
]
+werkzeug = [
+ {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
+ {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
+]
diff --git a/pyproject.toml b/pyproject.toml
index bf6bc58..939f1f7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -9,6 +9,7 @@ license = "MIT"
python = "^3.8"
requests = "^2.24.0"
typing_extensions = "^3.7.4"
+flask = "^1.1.2"
[tool.poetry.dev-dependencies]
flake8 = "^3.8.3"
From d535da8977d7481d1f4bba9f39300b788f50e869 Mon Sep 17 00:00:00 2001
From: Scoder12 <34356756+Scoder12@users.noreply.github.com>
Date: Mon, 27 Jul 2020 17:21:50 -0700
Subject: [PATCH 4/5] Import database relatively
---
src/replit/maqpi/__init__.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/replit/maqpi/__init__.py b/src/replit/maqpi/__init__.py
index a6f61ce..20589f5 100644
--- a/src/replit/maqpi/__init__.py
+++ b/src/replit/maqpi/__init__.py
@@ -8,10 +8,8 @@ from . import html
from .app import App
from .html import Page, Paragraph
from .utils import sign_in_snippet, signin
+from ..database import db
-# TODO: import new db package package name
-
-db = ReplitDb(os.environ["REPLIT_DB_URL"])
auth = LocalProxy(lambda: flask.request.auth)
signed_in = LocalProxy(lambda: flask.request.signed_in)
From 4c6a7ec0bbc0a6f6d75191c0b8558657288c81f0 Mon Sep 17 00:00:00 2001
From: Scoder12 <34356756+Scoder12@users.noreply.github.com>
Date: Mon, 27 Jul 2020 17:22:12 -0700
Subject: [PATCH 5/5] Import maqpi in init
---
src/replit/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/replit/__init__.py b/src/replit/__init__.py
index d0a010a..f2652cf 100644
--- a/src/replit/__init__.py
+++ b/src/replit/__init__.py
@@ -1,4 +1,5 @@
"""The replit python module."""
+from . import maqpi
from .audio import Audio
from .database import db