structables 0.3.5__tar.gz → 0.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- structables-0.3.7/.env.example +3 -0
- structables-0.3.7/.forgejo/workflows/docker.yml +33 -0
- {structables-0.3.5 → structables-0.3.7}/.gitignore +7 -4
- structables-0.3.7/Dockerfile +17 -0
- {structables-0.3.5 → structables-0.3.7}/PKG-INFO +20 -5
- {structables-0.3.5 → structables-0.3.7}/README.md +18 -4
- structables-0.3.7/docker-compose-example.yml +18 -0
- structables-0.3.7/entrypoint.sh +18 -0
- {structables-0.3.5 → structables-0.3.7}/pyproject.toml +2 -1
- {structables-0.3.5 → structables-0.3.7}/src/structables/config.py +1 -1
- structables-0.3.7/src/structables/main.py +42 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/routes/main.py +15 -1
- structables-0.3.5/src/structables/main.py +0 -23
- structables-0.3.5/src/structables/static/dist/css/bootstrap.min.css +0 -6
- structables-0.3.5/src/structables/static/dist/css/bootstrap.min.css.map +0 -1
- structables-0.3.5/src/structables/static/dist/js/bootstrap.bundle.min.js +0 -7
- structables-0.3.5/src/structables/static/dist/js/bootstrap.bundle.min.js.map +0 -1
- {structables-0.3.5 → structables-0.3.7}/.forgejo/workflows/release.yml +0 -0
- {structables-0.3.5 → structables-0.3.7}/LICENSE +0 -0
- {structables-0.3.5 → structables-0.3.7}/cronjob.txt +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/__init__.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/routes/__init__.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/routes/category.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/routes/contest.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/routes/member.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/routes/proxy.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/static/css/style.css +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/static/img/logo.png +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/static/img/logo_lg.png +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/static/img/magnifying-glass-solid.svg +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/400.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/404.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/429.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/500.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/archives.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/article-review.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/article.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/base.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/category.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/collection.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/contest.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/contests.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/footer.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/header.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/iframe.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/index.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/member-instructables.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/member.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/privacypolicy.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/projects.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/sitemap.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/templates/style.html +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/utils/data.py +0 -0
- {structables-0.3.5 → structables-0.3.7}/src/structables/utils/helpers.py +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Docker CI/CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
docker:
|
|
10
|
+
name: Docker Build and Push to Docker Hub
|
|
11
|
+
container:
|
|
12
|
+
image: node:20-bookworm
|
|
13
|
+
steps:
|
|
14
|
+
- name: Install dependencies
|
|
15
|
+
run: |
|
|
16
|
+
apt update
|
|
17
|
+
apt install -y docker.io
|
|
18
|
+
- name: Set up QEMU
|
|
19
|
+
uses: docker/setup-qemu-action@v3
|
|
20
|
+
- name: Set up Docker Buildx
|
|
21
|
+
uses: docker/setup-buildx-action@v3
|
|
22
|
+
- name: Login to Docker Hub
|
|
23
|
+
uses: docker/login-action@v3
|
|
24
|
+
with:
|
|
25
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
26
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
27
|
+
- name: Build and push to Docker Hub
|
|
28
|
+
uses: docker/build-push-action@v5
|
|
29
|
+
with:
|
|
30
|
+
push: true
|
|
31
|
+
tags: |
|
|
32
|
+
privatecoffee/structables:latest
|
|
33
|
+
privatecoffee/structables:${{ env.GITHUB_REF_NAME }}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
FROM alpine:3.20
|
|
2
|
+
|
|
3
|
+
ENV APP_ENV=/opt/venv
|
|
4
|
+
ENV PATH="${APP_ENV}/bin:$PATH"
|
|
5
|
+
|
|
6
|
+
RUN apk add --no-cache py3-pip uwsgi-python3 && \
|
|
7
|
+
python3 -m venv $APP_ENV && \
|
|
8
|
+
$APP_ENV/bin/pip install --no-cache-dir pip structables && \
|
|
9
|
+
adduser -S -D -H structables
|
|
10
|
+
|
|
11
|
+
COPY entrypoint.sh /entrypoint.sh
|
|
12
|
+
|
|
13
|
+
EXPOSE 8002
|
|
14
|
+
|
|
15
|
+
USER structables
|
|
16
|
+
|
|
17
|
+
ENTRYPOINT ["/entrypoint.sh"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: structables
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: A simple frontend for Instructables
|
|
5
5
|
Project-URL: Homepage, https://git.private.coffee/privatecoffee/structables
|
|
6
6
|
Project-URL: Bug Tracker, https://git.private.coffee/privatecoffee/structables/issues
|
|
@@ -674,6 +674,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
674
674
|
Requires-Python: >=3.10
|
|
675
675
|
Requires-Dist: bs4
|
|
676
676
|
Requires-Dist: flask
|
|
677
|
+
Requires-Dist: markdown2[all]
|
|
677
678
|
Description-Content-Type: text/markdown
|
|
678
679
|
|
|
679
680
|
<img align="right" src="src/structables/static/img/logo.png">
|
|
@@ -691,9 +692,10 @@ An open source alternative front-end to Instructables. This is a fork of <a href
|
|
|
691
692
|
|
|
692
693
|
## Instances
|
|
693
694
|
|
|
694
|
-
| URL
|
|
695
|
-
|
|
|
696
|
-
| [
|
|
695
|
+
| URL | Provided by | Country | Comments |
|
|
696
|
+
| ----------------------------------------------------------------- | ----------------------------------------- | ------- | -------- |
|
|
697
|
+
| [structables.private.coffee](https://structables.private.coffee/) | [Private.coffee](https://private.coffee/) | Austria | |
|
|
698
|
+
| [structables.bloat.cat](https://structables.bloat.cat/) | [Bloat.cat](https://bloat.cat) | Romania | |
|
|
697
699
|
|
|
698
700
|
To add your own instance to this list, please open a pull request or issue.
|
|
699
701
|
|
|
@@ -705,7 +707,7 @@ Of course, you can also join our [Matrix room](https://matrix.pcof.fi/#/#structa
|
|
|
705
707
|
|
|
706
708
|
## Run your own instance
|
|
707
709
|
|
|
708
|
-
### Production
|
|
710
|
+
### Production: Manual
|
|
709
711
|
|
|
710
712
|
1. Create a virtual environment: `python3 -m venv venv`
|
|
711
713
|
2. Activate the virtual environment: `source venv/bin/activate`
|
|
@@ -714,6 +716,19 @@ Of course, you can also join our [Matrix room](https://matrix.pcof.fi/#/#structa
|
|
|
714
716
|
5. Point your reverse proxy to http://localhost:8002 and (optionally) serve static files from the `venv/lib/pythonX.XX/site-packages/structables/static` directory
|
|
715
717
|
6. Connect to your instance under your domain
|
|
716
718
|
|
|
719
|
+
### Production: Docker
|
|
720
|
+
|
|
721
|
+
1. Copy `.env.example` to `.env` and adjust the settings as necessary
|
|
722
|
+
2. Copy `docker-compose-example.yml` to `docker-compose.yml` and adjust it as necessary, for example modifying resource limits or changing the port/host configuration
|
|
723
|
+
3. Build and run the Docker container:
|
|
724
|
+
|
|
725
|
+
```sh
|
|
726
|
+
docker-compose up [-d]
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
4. Point your reverse proxy to http://127.0.0.1:8002 (or your chosen port, if you modified it) and (optionally) serve static files from `structables/static`
|
|
730
|
+
5. Connect to your instance under your domain
|
|
731
|
+
|
|
717
732
|
### Development
|
|
718
733
|
|
|
719
734
|
1. Clone the repository: `git clone https://git.private.coffee/privatecoffee/structables.git && cd structables`
|
|
@@ -13,9 +13,10 @@ An open source alternative front-end to Instructables. This is a fork of <a href
|
|
|
13
13
|
|
|
14
14
|
## Instances
|
|
15
15
|
|
|
16
|
-
| URL
|
|
17
|
-
|
|
|
18
|
-
| [
|
|
16
|
+
| URL | Provided by | Country | Comments |
|
|
17
|
+
| ----------------------------------------------------------------- | ----------------------------------------- | ------- | -------- |
|
|
18
|
+
| [structables.private.coffee](https://structables.private.coffee/) | [Private.coffee](https://private.coffee/) | Austria | |
|
|
19
|
+
| [structables.bloat.cat](https://structables.bloat.cat/) | [Bloat.cat](https://bloat.cat) | Romania | |
|
|
19
20
|
|
|
20
21
|
To add your own instance to this list, please open a pull request or issue.
|
|
21
22
|
|
|
@@ -27,7 +28,7 @@ Of course, you can also join our [Matrix room](https://matrix.pcof.fi/#/#structa
|
|
|
27
28
|
|
|
28
29
|
## Run your own instance
|
|
29
30
|
|
|
30
|
-
### Production
|
|
31
|
+
### Production: Manual
|
|
31
32
|
|
|
32
33
|
1. Create a virtual environment: `python3 -m venv venv`
|
|
33
34
|
2. Activate the virtual environment: `source venv/bin/activate`
|
|
@@ -36,6 +37,19 @@ Of course, you can also join our [Matrix room](https://matrix.pcof.fi/#/#structa
|
|
|
36
37
|
5. Point your reverse proxy to http://localhost:8002 and (optionally) serve static files from the `venv/lib/pythonX.XX/site-packages/structables/static` directory
|
|
37
38
|
6. Connect to your instance under your domain
|
|
38
39
|
|
|
40
|
+
### Production: Docker
|
|
41
|
+
|
|
42
|
+
1. Copy `.env.example` to `.env` and adjust the settings as necessary
|
|
43
|
+
2. Copy `docker-compose-example.yml` to `docker-compose.yml` and adjust it as necessary, for example modifying resource limits or changing the port/host configuration
|
|
44
|
+
3. Build and run the Docker container:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
docker-compose up [-d]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
4. Point your reverse proxy to http://127.0.0.1:8002 (or your chosen port, if you modified it) and (optionally) serve static files from `structables/static`
|
|
51
|
+
5. Connect to your instance under your domain
|
|
52
|
+
|
|
39
53
|
### Development
|
|
40
54
|
|
|
41
55
|
1. Clone the repository: `git clone https://git.private.coffee/privatecoffee/structables.git && cd structables`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
services:
|
|
2
|
+
structables:
|
|
3
|
+
container_name: structables
|
|
4
|
+
restart: unless-stopped
|
|
5
|
+
build: .
|
|
6
|
+
ports:
|
|
7
|
+
- "127.0.0.1:8002:8002"
|
|
8
|
+
env_file: .env
|
|
9
|
+
security_opt:
|
|
10
|
+
- no-new-privileges:true
|
|
11
|
+
cap_drop:
|
|
12
|
+
- ALL
|
|
13
|
+
read_only: true
|
|
14
|
+
deploy:
|
|
15
|
+
resources:
|
|
16
|
+
limits:
|
|
17
|
+
cpus: '0.5'
|
|
18
|
+
memory: 300M
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
args="--plugin python3 \
|
|
3
|
+
--http-socket 0.0.0.0:$PORT \
|
|
4
|
+
--master \
|
|
5
|
+
--module structables.main:app \
|
|
6
|
+
-H /opt/venv"
|
|
7
|
+
|
|
8
|
+
if [ "$UWSGI_PROCESSES" ]
|
|
9
|
+
then
|
|
10
|
+
args="$args --processes $UWSGI_PROCESSES"
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [ "$UWSGI_THREADS" ]
|
|
14
|
+
then
|
|
15
|
+
args="$args --threads $UWSGI_THREADS"
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
exec /usr/sbin/uwsgi $args
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "structables"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.7"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Private.coffee Team", email="support@private.coffee" },
|
|
10
10
|
]
|
|
@@ -20,6 +20,7 @@ classifiers = [
|
|
|
20
20
|
dependencies = [
|
|
21
21
|
"flask",
|
|
22
22
|
"bs4",
|
|
23
|
+
"markdown2[all]",
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
[project.scripts]
|
|
@@ -6,7 +6,7 @@ class Config:
|
|
|
6
6
|
LISTEN_HOST = os.environ.get("STRUCTABLES_LISTEN_HOST", "127.0.0.1")
|
|
7
7
|
INVIDIOUS = os.environ.get("STRUCTABLES_INVIDIOUS")
|
|
8
8
|
UNSAFE = os.environ.get("STRUCTABLES_UNSAFE", False)
|
|
9
|
-
PRIVACY_FILE = os.environ.get("STRUCTABLES_PRIVACY_FILE"
|
|
9
|
+
PRIVACY_FILE = os.environ.get("STRUCTABLES_PRIVACY_FILE")
|
|
10
10
|
|
|
11
11
|
@staticmethod
|
|
12
12
|
def init_app(app):
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
from flask import Flask
|
|
4
|
+
import threading
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from .config import Config
|
|
8
|
+
from .routes import init_routes
|
|
9
|
+
from .utils.data import update_data
|
|
10
|
+
from .utils.helpers import get_typesense_api_key
|
|
11
|
+
|
|
12
|
+
app = Flask(__name__, template_folder="templates", static_folder="static")
|
|
13
|
+
app.config.from_object(Config)
|
|
14
|
+
app.typesense_api_key = get_typesense_api_key()
|
|
15
|
+
|
|
16
|
+
init_routes(app)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def background_update_data(app):
|
|
20
|
+
"""Runs the update_data function every 5 minutes.
|
|
21
|
+
|
|
22
|
+
This replaces the need for a cron job to update the data.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
app (Flask): The Flask app instance.
|
|
26
|
+
"""
|
|
27
|
+
while True:
|
|
28
|
+
update_data(app)
|
|
29
|
+
time.sleep(300)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
threading.Thread(target=background_update_data, args=(app,), daemon=True).start()
|
|
34
|
+
app.run(
|
|
35
|
+
port=app.config["PORT"],
|
|
36
|
+
host=app.config["LISTEN_HOST"],
|
|
37
|
+
debug=app.config["DEBUG"],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == "__main__":
|
|
42
|
+
main()
|
|
@@ -4,6 +4,7 @@ from urllib.error import HTTPError
|
|
|
4
4
|
from bs4 import BeautifulSoup
|
|
5
5
|
from urllib.parse import quote
|
|
6
6
|
from werkzeug.exceptions import InternalServerError
|
|
7
|
+
from markdown2 import Markdown
|
|
7
8
|
from traceback import print_exc
|
|
8
9
|
import pathlib
|
|
9
10
|
import json
|
|
@@ -342,11 +343,24 @@ def init_main_routes(app):
|
|
|
342
343
|
|
|
343
344
|
content = "No privacy policy found."
|
|
344
345
|
|
|
345
|
-
path = app.config.get("PRIVACY_FILE"
|
|
346
|
+
path = app.config.get("PRIVACY_FILE")
|
|
347
|
+
|
|
348
|
+
if not path:
|
|
349
|
+
if pathlib.Path("privacy.md").exists():
|
|
350
|
+
path = "privacy.md"
|
|
351
|
+
|
|
352
|
+
elif pathlib.Path("privacy.txt").exists():
|
|
353
|
+
path = "privacy.txt"
|
|
346
354
|
|
|
347
355
|
try:
|
|
348
356
|
with pathlib.Path(path).open() as f:
|
|
349
357
|
content = f.read()
|
|
358
|
+
|
|
359
|
+
print(path, content)
|
|
360
|
+
|
|
361
|
+
if path.endswith(".md"):
|
|
362
|
+
content = Markdown().convert(content)
|
|
363
|
+
|
|
350
364
|
except OSError:
|
|
351
365
|
pass
|
|
352
366
|
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
|
|
3
|
-
from flask import Flask
|
|
4
|
-
|
|
5
|
-
from .config import Config
|
|
6
|
-
from .routes import init_routes
|
|
7
|
-
from .utils.data import update_data
|
|
8
|
-
from .utils.helpers import get_typesense_api_key
|
|
9
|
-
|
|
10
|
-
app = Flask(__name__, template_folder="templates", static_folder="static")
|
|
11
|
-
app.config.from_object(Config)
|
|
12
|
-
app.typesense_api_key = get_typesense_api_key()
|
|
13
|
-
|
|
14
|
-
init_routes(app)
|
|
15
|
-
|
|
16
|
-
def main():
|
|
17
|
-
app.run(port=app.config['PORT'], host=app.config['LISTEN_HOST'], debug=app.config['DEBUG'])
|
|
18
|
-
|
|
19
|
-
if __name__ == "__main__":
|
|
20
|
-
main()
|
|
21
|
-
|
|
22
|
-
# Initialize data when the server starts
|
|
23
|
-
update_data(app)
|