diff --git a/.gitignore b/.gitignore
index e2082e9..532bee7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
*.un~
*.swp
*.sh
+thsf.log
+thsf_venv
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..dd49821
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,6 @@
+global-exclude *.pyc
+global-exclude build
+global-exclude __pycache__
+
+include src/thsf/templates/*.*
+include src/thsf/static/**/*.*
diff --git a/Makefile b/Makefile
index 9ac38b3..c097280 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,32 @@
-.PHONY: install
+.PHONY: clean install run stop
install:
- echo "We Make P0RN"
+ set -e ;\
+ THSF_DIR=$$(pwd); \
+ echo [+] Déploiement dans $$THSF_DIR; \
+ python3 -m venv thsf_venv; \
+ . thsf_venv/bin/activate; \
+ pip install -r requirements.txt ;\
+ pip install . ;\
+ pip install gunicorn;
+
+run:
+ set -e ;\
+ THSF_DIR=$$(pwd); \
+ echo [+] Démarrage dans $$THSF_DIR; \
+ . thsf_venv/bin/activate; \
+ thsf_venv/bin/gunicorn -D -p thsf.pid -w 4 -b 127.0.0.1:8042 'thsf:app'
+
+stop:
+ -set -e;\
+ kill -15 $$(cat thsf.pid); \
+ rm thsf.pid
+
+clean:
+ -set -e ;\
+ rm -Rf ./build ;\
+ rm -Rf ./src/thsf.egg-info; \
+ . thsf_venv/bin/activate; \
+ pip uninstall thsf -y
+
+all: clean stop install run
diff --git a/README.md b/README.md
index 1076d37..704aa32 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,9 @@ Lorsque la demande de fusion sera acceptée (vous pouvez auto-accepter vos deman
### Personnalisation de la publication
-Afin de rendre le processus plus souple, il est possible de personnaliser la livraison en plaçant **à la racine du dépôt** un fichier `Makefile` contenant une cible `install` qui sera systématiquement exécutée.
+Afin de rendre le processus plus souple, il est possible de personnaliser la livraison en plaçant **à la racine du dépôt** un fichier `Makefile` contenant une cible `all` qui sera systématiquement exécutée.
-C'est dans cette cible `install` que vous pourrez mettre toutes vos commandes personnalisées, typiquement l'installation de modules `npm`.
+C'est dans cette cible `all` que vous pourrez mettre toutes vos commandes personnalisées, typiquement l'installation de modules `python`, etc.
Le processus de publication est le suivant:
@@ -26,7 +26,7 @@ Le processus de publication est le suivant:
2. La branche `master` du présent dépôt est cloné sur le serveur hébergeant le site du **THSF**
-3. Si un fichier `Makefile` se trouve **à la racine du dépôt**, la cible `install` (i.e: `make install`) est automatiquement exécutée.
+3. Si un fichier `Makefile` se trouve **à la racine du dépôt**, la cible `all` (i.e: `make all`) est automatiquement exécutée.
## Contrôle de qualité et tests
diff --git a/config.yml b/config.yml
new file mode 100644
index 0000000..3410596
--- /dev/null
+++ b/config.yml
@@ -0,0 +1,30 @@
+---
+log:
+ version: 1
+ formatters:
+ default:
+ format: '[%(asctime)-20s][%(levelname)-8s][%(funcName)-20s]: %(message)s'
+ handlers:
+ wsgi:
+ class: logging.FileHandler
+ filename: thsf.log
+ formatter: default
+ loggers:
+ thsf:
+ handlers: [wsgi]
+ propagate: no
+ root:
+ level: INFO
+ handlers: [wsgi]
+app:
+ secret_key: xxx
+ languages:
+ - fr
+ name: THSF
+ real_url: https://www.thsf.net
+pretalx:
+ url: https://23.thsf.net
+ apikey: sdfsdfsdf
+ event: thsf-2023
+ schedule: wip
+
diff --git a/index.html b/index.html
deleted file mode 100644
index 372d98e..0000000
--- a/index.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- THSF 2023: Extractivisme
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..dc40988
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,10 @@
+[build-system]
+requires = ["setuptools>=62",
+ "build",
+ "wheel"]
+build-backend = "setuptools.build_meta"
+
+[tool.pytest.ini_options]
+pythonpath = [
+ "src"
+]
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..1e40446
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+build
+wheel
+flask
+gunicorn
+pyYAML
diff --git a/resources/THSF23_WEBSITE_BANNER.svg b/resources/THSF23_WEBSITE_BANNER.svg
new file mode 100644
index 0000000..f680b45
--- /dev/null
+++ b/resources/THSF23_WEBSITE_BANNER.svg
@@ -0,0 +1,611 @@
+
+
+
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..8320658
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,48 @@
+[metadata]
+version = 0.0.1
+classifiers =
+ Programming Language :: Python :: 3
+ License :: OSI Approved :: MIT License
+ Operating System :: OS Independent
+url = https://git.tetalab.org/tetalab/thsf.net
+description = "THSF website"
+name = thsf
+long_description = file: README.md
+long_description_content_type = text/markdown
+author = Doug Le Tough
+author_email = doug@redatomik.org
+
+[options]
+package_dir =
+ = src
+packages = find:
+include_package_data = True
+python_requires = >=3.8
+install_requires =
+ flask
+ gunicorn
+ pyYAML
+
+[options.packages.find]
+where = src
+
+[options.extras_require]
+dev =
+ twine
+ build
+ wheel>=0.37.0
+ flake8>=4.0.1
+ flake8-breakpoint>=1.1.0
+ flake8-builtins>=1.5.3
+ flake8-print>=4.0.0
+ flake8-return>=1.1.3
+ pep8-naming>=0.8.2
+ setuptools>=60.9.2
+ pylint>=2.12.2
+
+[flake8]
+ignore = E111
+exclude = .git,__pycache__,build,dist, thot-cli-venv
+max-line-length = 160
+use-flake8-tabs = true
+tab-width = 2
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..b908cbe
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,3 @@
+import setuptools
+
+setuptools.setup()
diff --git a/src/thsf/__init__.py b/src/thsf/__init__.py
new file mode 100644
index 0000000..fcbf56e
--- /dev/null
+++ b/src/thsf/__init__.py
@@ -0,0 +1,98 @@
+import sys
+import logging
+from logging import config
+import yaml
+from flask import Flask, render_template, redirect, request, url_for
+
+
+# ------------------------------------------------------------------------------
+# -- Configuration
+# ------------------------------------------------------------------------------
+class AppConfig:
+ """ Flask application config """
+ CONFIG_FILENAME = "config.yml"
+
+
+# ------------------------------------------------------------------------------
+# -- Application
+# ------------------------------------------------------------------------------
+logger = logging.getLogger('wsgi')
+app = Flask(__name__)
+
+
+# ------------------------------------------------------------------------------
+# -- Local configuration
+# ------------------------------------------------------------------------------
+app.config.from_object(__name__ + '.AppConfig')
+try:
+ with open(app.config["CONFIG_FILENAME"], "r") as local_config_file:
+ app.local_config = yaml.load(local_config_file, Loader=yaml.SafeLoader)
+ app.config["SECRET_KEY"] = app.local_config["app"]["secret_key"]
+ app.config["LANGUAGES"] = app.local_config["app"]["languages"]
+ config.dictConfig(app.local_config["log"])
+except Exception as err:
+ logger.critical("[{}] {}".format(err.__class__, str(err)))
+ sys.exit(1)
+
+
+# ------------------------------------------------------------------------------
+# -- Tools
+# ------------------------------------------------------------------------------
+@app.errorhandler(404)
+def page_not_found(err):
+ return redirect(url_for('index'))
+
+
+# ------------------------------------------------------------------------------
+# -- Routes
+# ------------------------------------------------------------------------------
+@app.route('/favicon.ico', methods=['GET'])
+def favicon():
+ return redirect(url_for('static', filename='images/favicon.png'))
+
+@app.route('/', methods=['GET'])
+def index():
+ return render_template("index.html")
+
+@app.route('/planning', methods=['GET'])
+def planning():
+ return "planning"
+
+@app.route('/concerts', methods=['GET'])
+def concerts():
+ return "concerts"
+
+@app.route('/djsets', methods=['GET'])
+def djsets():
+ return "djsets"
+
+@app.route('/exhibitions', methods=['GET'])
+def exhibitions():
+ return "exhibitions"
+
+@app.route('/lighttalks', methods=['GET'])
+def lighttalks():
+ return "lighttalks"
+
+@app.route('/paneldiscussions', methods=['GET'])
+def paneldiscussions():
+ return "paneldiscussions"
+
+@app.route('/screenings', methods=['GET'])
+def screenings():
+ return "screenings"
+
+@app.route('/talks', methods=['GET'])
+def talks():
+ return "talks"
+
+@app.route('/workshops', methods=['GET'])
+def workshops():
+ return "workshops"
+
+
+# ------------------------------------------------------------------------------
+# -- Main
+# ------------------------------------------------------------------------------
+if __name__ == '__main__':
+ app.run(host='127.0.0.1', port=5000, debug=True)
diff --git a/src/thsf/static/css/style.css b/src/thsf/static/css/style.css
new file mode 100644
index 0000000..b4f8bc4
--- /dev/null
+++ b/src/thsf/static/css/style.css
@@ -0,0 +1,111 @@
+@font-face {
+ font-family: pfdintextcomppromedium;
+ src: url(../fonts/PFDinTextCompPro-Medium.ttf);
+}
+
+@font-face {
+ font-family: pfdintextcompprothin;
+ src: url(../fonts/PFDinTextCompPro-Thin.ttf);
+}
+
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ background-color: #e6007e;
+ background-repeat: no-repeat;
+ background-size: auto;
+ background-position-x: center;
+ font-family: pfdintextcomppromedium;
+}
+
+span.header {
+ font-size: 9.75em;
+ font-weight: bold;
+}
+
+
+span.subheader {
+ margin: 0;
+ font-size: 3.47em;
+ font-weight: thin;
+}
+
+span.place {
+ margin: 0;
+ font-size: 2.145em;
+}
+
+.white {
+ color: #ffffff;
+}
+
+.black {
+ color: #1A000D;
+}
+
+.thin {
+ font-family: pfdintextcompprothin;
+}
+
+.bold {
+ font-family: pfdintextcomppromedium;
+}
+
+#main_wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+}
+
+#header {
+ text-align: center;
+ margin-bottom: -3em;
+}
+
+#logo_wrapper {
+ margin-top: 1em;
+ width: 40em;
+}
+
+img.logo {
+ width: inherit;
+}
+
+#navbar_wrapper {
+ margin-top: 1em;
+ display: flex;
+ flex-direction: line;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 2em;
+}
+
+.button {
+ font-size: 4em;
+ transition-property: color;
+ transition-duration: 1s;
+}
+
+.button:hover {
+ color: #ffffff;
+ cursor: pointer;
+}
+
+
+#cursorbar {
+ margin-top: 1em;
+}
+
+.cursor {
+ width: 0;
+ height: 0;
+ border-left: 0.75em solid transparent;
+ border-right: 0.75em solid transparent;
+ border-bottom: 0.75em solid #000000;
+}
diff --git a/fonts/PFDinTextCompPro-Medium.ttf b/src/thsf/static/fonts/PFDinTextCompPro-Medium.ttf
similarity index 100%
rename from fonts/PFDinTextCompPro-Medium.ttf
rename to src/thsf/static/fonts/PFDinTextCompPro-Medium.ttf
diff --git a/fonts/PFDinTextCompPro-Thin.ttf b/src/thsf/static/fonts/PFDinTextCompPro-Thin.ttf
similarity index 100%
rename from fonts/PFDinTextCompPro-Thin.ttf
rename to src/thsf/static/fonts/PFDinTextCompPro-Thin.ttf
diff --git a/fonts/Uni Sans Bold.otf b/src/thsf/static/fonts/Uni Sans Bold.otf
similarity index 100%
rename from fonts/Uni Sans Bold.otf
rename to src/thsf/static/fonts/Uni Sans Bold.otf
diff --git a/fonts/Uni Sans Book.otf b/src/thsf/static/fonts/Uni Sans Book.otf
similarity index 100%
rename from fonts/Uni Sans Book.otf
rename to src/thsf/static/fonts/Uni Sans Book.otf
diff --git a/src/thsf/static/fonts/fontawesome-free-6.4.0-web.zip b/src/thsf/static/fonts/fontawesome-free-6.4.0-web.zip
new file mode 100644
index 0000000..c1bd796
Binary files /dev/null and b/src/thsf/static/fonts/fontawesome-free-6.4.0-web.zip differ
diff --git a/images/affiche_v1.png b/src/thsf/static/images/affiche_v1.png
similarity index 100%
rename from images/affiche_v1.png
rename to src/thsf/static/images/affiche_v1.png
diff --git a/images/bg.png b/src/thsf/static/images/bg.png
similarity index 100%
rename from images/bg.png
rename to src/thsf/static/images/bg.png
diff --git a/images/favicon.png b/src/thsf/static/images/favicon.png
similarity index 100%
rename from images/favicon.png
rename to src/thsf/static/images/favicon.png
diff --git a/src/thsf/static/images/logo.svg b/src/thsf/static/images/logo.svg
new file mode 100644
index 0000000..c2b921e
--- /dev/null
+++ b/src/thsf/static/images/logo.svg
@@ -0,0 +1,301 @@
+
+
+
+
diff --git a/images/pretalx-header.png b/src/thsf/static/images/pretalx-header.png
similarity index 100%
rename from images/pretalx-header.png
rename to src/thsf/static/images/pretalx-header.png
diff --git a/src/thsf/templates/base.html b/src/thsf/templates/base.html
new file mode 100644
index 0000000..2d2dd7b
--- /dev/null
+++ b/src/thsf/templates/base.html
@@ -0,0 +1,22 @@
+
+
+
+ THSF 2023: S/Extraire
+
+
+
+
+
+ {% block headers %}
+ {% endblock %}
+
+
+
+{% block content %}
+{% endblock %}
+
+
diff --git a/src/thsf/templates/index.html b/src/thsf/templates/index.html
new file mode 100644
index 0000000..e3736ab
--- /dev/null
+++ b/src/thsf/templates/index.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/src/thsf/templates/planning.html b/src/thsf/templates/planning.html
new file mode 100644
index 0000000..0630c4f
--- /dev/null
+++ b/src/thsf/templates/planning.html
@@ -0,0 +1,18 @@
+{% extends "base.html" %}
+{% block headers %}
+
+{% endblock %}
+
+{% block content %}
+
+{% endblock %}
diff --git a/src/thsf_wsgi.py b/src/thsf_wsgi.py
new file mode 100644
index 0000000..f204296
--- /dev/null
+++ b/src/thsf_wsgi.py
@@ -0,0 +1,5 @@
+from thsf import app
+
+if __name__ == "__main__":
+ application = app
+ application.run(host="127.0.0.1", port=8043)
diff --git a/styles/main.css b/styles/main.css
deleted file mode 100644
index 2c803c8..0000000
--- a/styles/main.css
+++ /dev/null
@@ -1,151 +0,0 @@
-@font-face {
- font-family: pfdintextcomppro;
- src: url(../fonts/PFDinTextCompPro-Medium.ttf);
-}
-
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- font-family: pfdintextcomppro;
-}
-
-body {
- background-color: #e6007e;
- background-image: url('../images/bg.png');
- background-repeat: no-repeat;
- background-size: auto;
- background-position-x: center;
- /* overflow: hidden; */
-}
-
-#thsf-schedule-wrapper {
- position: fixed;
- top: 220px;
- left: 50%;
- transform: translateX(-50%);
- width: 50%;
- height: 90%;
- overflow: auto;
- margin-bottom: 10px;
-}
-
-
-ul {
- overflow: hidden;
- perspective: 900px;
- list-style: none;
- height: 100vh;
- max-height: 800px;
- min-height: 400px;
- text-align: center;
-}
-
-@keyframes width-sway {
- 0%, 100% {
- width: 500px;
- }
- 50% {
- width: 100%;
- }
-}
-li {
- position: absolute;
- top: 0;
- margin: auto;
- width: 100%;
- transform: translateY(100vh);
- font-size: 6rem;
- font-family: pfdintextcomppro;
- font-weight: bold;
- color: #ffffdd;
- animation: 5.3333333333s spiral-staircase linear infinite;
- white-space: nowrap;
-}
-
-li:nth-child(1) {
- animation-delay: 0.3333333333s;
-}
-
-li:nth-child(2) {
- animation-delay: 0.6666666667s;
-}
-
-li:nth-child(3) {
- animation-delay: 1s;
-}
-
-li:nth-child(4) {
- animation-delay: 1.3333333333s;
-}
-
-li:nth-child(5) {
- animation-delay: 1.6666666667s;
-}
-
-li:nth-child(6) {
- animation-delay: 2s;
-}
-
-li:nth-child(7) {
- animation-delay: 2.3333333333s;
-}
-
-li:nth-child(8) {
- animation-delay: 2.6666666667s;
-}
-
-li:nth-child(9) {
- animation-delay: 3s;
-}
-
-li:nth-child(10) {
- animation-delay: 3.3333333333s;
-}
-
-li:nth-child(11) {
- animation-delay: 3.6666666667s;
-}
-
-li:nth-child(12) {
- animation-delay: 4s;
-}
-
-li:nth-child(13) {
- animation-delay: 4.3333333333s;
-}
-
-li:nth-child(14) {
- animation-delay: 4.6666666667s;
-}
-
-li:nth-child(15) {
- animation-delay: 5s;
-}
-
-li:nth-child(16) {
- animation-delay: 5.3333333333s;
-}
-
-@keyframes spiral-staircase {
- 0% {
- transform: rotateY(90deg) translateY(105vh) rotate(0deg) scale(0);
- opacity: 0;
- }
- 40% {
- transform: rotateY(90deg) translateY(61vh) rotate(0deg) scale(0);
- opacity: 0;
- }
- 50% {
- transform: rotateY(0deg) translateY(55vh) rotate(0deg) scale(0.50);
- opacity: 1;
- }
- 75% {
- transform: rotateY(-60deg) translateY(27.5vh) rotate(0deg) scale(1);
- opacity: 1;
- }
- 100% {
- transform: rotateY(-90deg) translateY(-5vh) rotate(0deg) scale(1.2);
- opacity: 0;
- }
-}