Compare commits

..

No commits in common. "main" and "feat/handle-pending-events" have entirely different histories.

19 changed files with 79 additions and 127 deletions

View File

@ -1,20 +0,0 @@
.ruff_cache
__pycache__
static
README.md
Makefile
.env
.env.example
venv
*.log
*.pid
pushpin
nginx
.deploy

View File

@ -1,10 +1,8 @@
SECRET_KEY=
# 'dev' or whatever for dev environment, otherwise 'prod' to enable production environment # 'dev' or whatever for dev environment, otherwise 'prod' to enable production environment
ENV=dev ENV=dev
# used only on production environment # used only on production environment
HOSTS= HOST=
POSTGRES_DB=mumui POSTGRES_DB=mumui
POSTGRES_USER=mumui POSTGRES_USER=mumui

10
.gitignore vendored
View File

@ -1,13 +1,9 @@
.ruff_cache .ruff_cache
__pycache__ __pycache__
db.sqlite3
venv venv
/static
static
*.log *.log
*.pid *.pid
docker-compose.override.yml
.env .env
.deploy

View File

@ -8,9 +8,12 @@ WORKDIR /app
RUN apt update && apt install -y RUN apt update && apt install -y
COPY . /app/ COPY startup.sh /app/
COPY requirements.txt /app/
RUN pip install -U pip RUN pip install -U pip
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
ENTRYPOINT [ "/app/startup.sh" ] ENTRYPOINT [ "/app/startup.sh" ]
EXPOSE 8000

View File

@ -1,39 +1,31 @@
-include .deploy/Makefile
PYTHON = venv/bin/python
VERSION := 0.1.0
format: format:
@$(PYTHON) -m black mumui/*.py deployment/*.py @./venv/bin/black mumui/*.py deployment/*.py
lint: lint:
@$(PYTHON) -m ruff . @./venv/bin/ruff .
dev: dev:
rm -rf venv rm -rf venv
python3 -m virtualenv venv python3 -m virtualenv venv
$(PYTHON) -m pip install -r requirements.txt ./venv/bin/pip install -r requirements.txt
$(PYTHON) -m pip install -r requirements-dev.txt ./venv/bin/pip install -r requirements-dev.txt
django: django:
docker build . -t mumui:local docker build . -t mumui:local
pushpin-local: pushpin-local:
cd pushpin && docker build . -t pushpin:mumui cd pushpin && docker build . -t pushpin:local
nginx-local: nginx-local:
cd nginx && docker build . -t nginx:mumui cd nginx && docker build . -t nginx:local
build: build:
$(MAKE) pushpin-local $(MAKE) pushpin-local
$(MAKE) nginx-local $(MAKE) nginx-local
$(MAKE) django $(MAKE) django
.PHONY: static run:
static: docker compose up
SECRET_KEY="" $(PYTHON) manage.py collectstatic --no-input
run: pushpin-local nginx-local django
@docker compose up
stop:
docker compose down

View File

@ -6,7 +6,7 @@
Well, i had to choose a project name and i have no idea... I was listening this [sh*t](https://www.youtube.com/watch?v=8ZawzGgwIbQ) and then a sudden flash came to me: **mumu-i** (**i** for interface, to be more professional). Well, i had to choose a project name and i have no idea... I was listening this [sh*t](https://www.youtube.com/watch?v=8ZawzGgwIbQ) and then a sudden flash came to me: **mumu-i** (**i** for interface, to be more professional).
You can test the application here: [mumui.sonak.fr](https://mumui.sonak.fr). You can test the application here: [mumui.thegux.fr](https://mumui.thegux.fr).
* username: **demo** * username: **demo**
* password: **demo1234** * password: **demo1234**

View File

@ -1,11 +1,5 @@
var es = null;
var start = function (url) { var start = function (url) {
if (es) { var es = new ReconnectingEventSource(url);
console.log("closing es", es);
es.close();
}
es = new ReconnectingEventSource(url);
console.log("url: " + url); console.log("url: " + url);
@ -67,17 +61,3 @@ var start = function (url) {
} }
}, false); }, false);
}; };
document.querySelectorAll(".btn-details").forEach(btn => {
btn.addEventListener("click", function(e) {
const durl = e.currentTarget.getAttribute("durl");
console.log("details url:", durl);
if (es) {
window.es.close()
console.log("closing sse....");
};
window.location = durl;
});
});

View File

@ -1,11 +1,5 @@
var start = function (url) { var start = function (url) {
if (window.es) { var es = new ReconnectingEventSource(url);
console.log("closing es", window.es);
window.es.close();
}
es = new ReconnectingEventSource(url);
window.es = es;
console.log("url: " + url); console.log("url: " + url);

View File

@ -4,7 +4,7 @@ from django.urls import path, include
from deployment.views import index, create, details, deploy, abort from deployment.views import index, create, details, deploy, abort
urlpatterns = [ urlpatterns = [
path("", index, name="deployments"), path("", index, name="deployment"),
path("create", create, name="deployment-create"), path("create", create, name="deployment-create"),
path("<uuid:deployment_id>", details, name="deployment-details"), path("<uuid:deployment_id>", details, name="deployment-details"),
path("<uuid:deployment_id>/deploy", deploy, name="deployment-launch"), path("<uuid:deployment_id>/deploy", deploy, name="deployment-launch"),
@ -13,7 +13,7 @@ urlpatterns = [
"events/<user_id>/", "events/<user_id>/",
include(django_eventstream.urls), include(django_eventstream.urls),
{"format-channels": ["deployment_{user_id}"]}, {"format-channels": ["deployment_{user_id}"]},
name="deployments-events", name="deployment-events",
), ),
path( path(
"events/<user_id>/<deployment_id>/", "events/<user_id>/<deployment_id>/",

View File

@ -71,9 +71,9 @@ def deploy(request, deployment_id):
launch_deploy.delay(deployment_id) launch_deploy.delay(deployment_id)
if page := request.GET.get("page", ""): if page := request.GET.get("page", ""):
return HttpResponseRedirect(f"/deployments?page={page}") return HttpResponseRedirect(f"/deployment?page={page}")
return HttpResponseRedirect("/deployments") return HttpResponseRedirect("/deployment")
def abort(request, deployment_id): def abort(request, deployment_id):
@ -95,7 +95,7 @@ def abort(request, deployment_id):
Event.send_details(deployment, progress) Event.send_details(deployment, progress)
Event.send(deployment) Event.send(deployment)
return HttpResponseRedirect(f"/deployments/{deployment.id}") return HttpResponseRedirect(f"/deployment/{deployment.id}")
def details(request, deployment_id): def details(request, deployment_id):
@ -116,7 +116,7 @@ def details(request, deployment_id):
deployment.delete() deployment.delete()
except Exception as e: except Exception as e:
return HttpResponseServerError(e) return HttpResponseServerError(e)
return HttpResponseRedirect("/deployments") return HttpResponseRedirect("/deployment")
return render( return render(
request, request,
@ -145,4 +145,4 @@ def create(request):
except Exception as e: except Exception as e:
return HttpResponseServerError(e) return HttpResponseServerError(e)
return HttpResponseRedirect("/deployments") return HttpResponseRedirect("/deployment")

View File

@ -2,15 +2,15 @@ version: '3'
services: services:
redis: redis:
image: redis/redis-stack-server:latest image: redis/redis-stack-server:latest
container_name: redis-mumui container_name: redis
networks: networks:
- mumui_network - mumui_network
volumes: volumes:
- redis_data:/data - redis_data:/data
pushpin: pushpin:
image: pushpin:mumui image: pushpin:local
container_name: pushpin-mumui container_name: pushpin
networks: networks:
- mumui_network - mumui_network
depends_on: depends_on:
@ -18,7 +18,7 @@ services:
postgres: postgres:
image: postgres:latest image: postgres:latest
container_name: postgres-mumui container_name: postgres
env_file: env_file:
- .env - .env
networks: networks:
@ -39,8 +39,8 @@ services:
- postgres - postgres
nginx: nginx:
image: nginx:mumui image: nginx:local
container_name: nginx-mumui container_name: nginx
networks: networks:
- mumui_network - mumui_network
volumes: volumes:

View File

@ -21,18 +21,15 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ["SECRET_KEY"] SECRET_KEY = "django-insecure-_c56%%c8%g%@5(3&thxi7ku2a&wst8lik*8@l0=#)ar)s86g36"
IS_PROD = os.getenv("ENV") == "prod" IS_PROD = os.getenv("ENV") == "prod"
HOST = "*" if not IS_PROD else os.getenv("HOST", "*")
HOSTS = ["*"]
if IS_PROD:
HOSTS = os.environ["HOSTS"].split(",")
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = not IS_PROD DEBUG = not IS_PROD
ALLOWED_HOSTS = [h.lstrip("https://") for h in HOSTS] ALLOWED_HOSTS = ["*"] if not IS_PROD else [HOST.lstrip("https://")]
# Application definition # Application definition
@ -142,4 +139,4 @@ LOGOUT_REDIRECT_URL = "home"
GRIP_URL = "http://pushpin:5561" GRIP_URL = "http://pushpin:5561"
EVENTSTREAM_CHANNELMANAGER_CLASS = "deployment.channels.DeploymentChannelManager" EVENTSTREAM_CHANNELMANAGER_CLASS = "deployment.channels.DeploymentChannelManager"
CSRF_TRUSTED_ORIGINS = HOSTS if IS_PROD else ["http://localhost:8080"] CSRF_TRUSTED_ORIGINS = [HOST] if IS_PROD else ["http://localhost:8080"]

View File

@ -21,6 +21,6 @@ from django.views.generic.base import TemplateView
urlpatterns = [ urlpatterns = [
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")), path("accounts/", include("django.contrib.auth.urls")),
path("deployments/", include("deployment.urls")), path("deployment/", include("deployment.urls")),
path("", TemplateView.as_view(template_name="home.html"), name="home"), path("", TemplateView.as_view(template_name="home.html"), name="home"),
] ]

View File

@ -1,3 +1,3 @@
FROM fanout/pushpin:latest FROM fanout/pushpin:latest
RUN echo "* api:8000" > /etc/pushpin/routes RUN echo "* mumui:8000" > /etc/pushpin/routes

View File

@ -3,6 +3,7 @@ pip install -r requirements.txt
python manage.py makemigrations python manage.py makemigrations
python manage.py migrate python manage.py migrate
python manage.py collectstatic --no-input
DJANGO_SUPERUSER_PASSWORD=${ADMIN_PASSWORD} python manage.py createsuperuser --noinput --username admin --email admin@admin.fr DJANGO_SUPERUSER_PASSWORD=${ADMIN_PASSWORD} python manage.py createsuperuser --noinput --username admin --email admin@admin.fr

View File

@ -4,6 +4,16 @@
{% block title %} Deployments board {% endblock %} {% block title %} Deployments board {% endblock %}
{% block headscript %}
<script src="{% static 'django_eventstream/json2.js' %}"></script>
<script src="{% static 'django_eventstream/eventsource.min.js' %}"></script>
<script src="{% static 'django_eventstream/reconnecting-eventsource.js' %}"></script>
{% endblock %}
{% block bodyattr %}
onload="start('{{ url|safe }}');"
{% endblock %}
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
@ -23,7 +33,9 @@
<th name="type">{{ deployment.type }}</th> <th name="type">{{ deployment.type }}</th>
<th name="status">{{ deployment.status }}</th> <th name="status">{{ deployment.status }}</th>
<th> <th>
<button class="btn btn-primary btn-sm btn btn-details" durl="{% url 'deployment-details' deployment.id %}">Details</button> <a href="{% url 'deployment-details' deployment.id %}">
<button class="btn btn-primary btn-sm">Details</button>
</a>
</th> </th>
{% if deployment.status == "FAILED" or deployment.status == "READY" %} {% if deployment.status == "FAILED" or deployment.status == "READY" %}
<th name="deploy"> <th name="deploy">
@ -73,10 +85,6 @@
{% endblock %} {% endblock %}
{% block script %} {% block script %}
<script src="{% static 'django_eventstream/json2.js' %}"></script>
<script src="{% static 'django_eventstream/eventsource.min.js' %}"></script>
<script src="{% static 'django_eventstream/reconnecting-eventsource.js' %}"></script>
<script src="{% static 'deployment/js/event_source.js' %}" /> <script src="{% static 'deployment/js/event_source.js' %}" />
</script> </script>
<script>start('{{ url|safe }}');</script>
{% endblock %} {% endblock %}

View File

@ -4,6 +4,20 @@
{% block title %} Deployment details: {{ deployment.name }} {% endblock %} {% block title %} Deployment details: {{ deployment.name }} {% endblock %}
{% block bodyattr %}
{% if deployment.status == "RUNNING" or deployment.status == "PENDING" %}
onload="start('{{ url|safe }}');"
{% endif %}
{% endblock %}
{% block headscript %}
{% if deployment.status == "RUNNING" or deployment.status == "PENDING" %}
<script src="{% static 'django_eventstream/json2.js' %}"></script>
<script src="{% static 'django_eventstream/eventsource.min.js' %}"></script>
<script src="{% static 'django_eventstream/reconnecting-eventsource.js' %}"></script>
{% endif %}
{% endblock %}
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
@ -57,7 +71,7 @@
{% csrf_token %} {% csrf_token %}
</form> </form>
{% endif %} {% endif %}
<button id="btn-back" durl="{% url 'deployments' %}" type="button" class="btn btn-secondary">Back</button> <button type="button" onclick="goBack()" class="btn btn-secondary">Back</button>
{% if deployment.status != "RUNNING" and deployment.status != "PENDING" %} {% if deployment.status != "RUNNING" and deployment.status != "PENDING" %}
<button form="delete-deployment" type="submit" class="btn btn-danger">Delete</button> <button form="delete-deployment" type="submit" class="btn btn-danger">Delete</button>
{% else %} {% else %}
@ -73,23 +87,12 @@
{% block script %} {% block script %}
{% if deployment.status == "RUNNING" or deployment.status == "PENDING" %} {% if deployment.status == "RUNNING" or deployment.status == "PENDING" %}
<script src="{% static 'django_eventstream/json2.js' %}"></script> <script src="{% static 'deployment/js/event_source_details.js' %}" />
<script src="{% static 'django_eventstream/eventsource.min.js' %}"></script> </script>
<script src="{% static 'django_eventstream/reconnecting-eventsource.js' %}"></script>
<script src="{% static 'deployment/js/event_source_details.js' %}" /></script>
<script>start('{{ url|safe }}');</script>
{% endif %} {% endif %}
<script> <script>
document.querySelector("#btn-back").addEventListener("click", function(e) { function goBack() {
const durl = e.currentTarget.getAttribute("durl"); window.location={% url 'deployment' %};
console.log("deployment url:", durl); }
if (window.es) {
window.es.close()
console.log("closing sse....");
};
window.location = durl;
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -15,7 +15,7 @@
<a class="nav-link" href="/">Home</a> <a class="nav-link" href="/">Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="{% url 'deployments' %}" class="nav-link">Deployments</a></li> <a href="{% url 'deployment' %}" class="nav-link">Deployments</a></li>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#">About</a></li> <a class="nav-link" href="#">About</a></li>

View File

@ -13,7 +13,7 @@
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
<div class="col-lg-6 col-md-8 col-sm-8"> <div class="col-lg-6 col-md-8 col-sm-8">
<div style="text-align: center;">Forget, i don't care... Please go on <div style="text-align: center;">Forget, i don't care... Please go on
<a href="{% url 'deployments' %}">Deployments</a> <a href="{% url 'deployment' %}">Deployments</a>
and enjoy the life ! and enjoy the life !
</div> </div>
</div> </div>