Compare commits
No commits in common. "main" and "feat/handle-pending-events" have entirely different histories.
main
...
feat/handl
@ -1,20 +0,0 @@
|
|||||||
.ruff_cache
|
|
||||||
__pycache__
|
|
||||||
|
|
||||||
static
|
|
||||||
|
|
||||||
README.md
|
|
||||||
Makefile
|
|
||||||
|
|
||||||
.env
|
|
||||||
.env.example
|
|
||||||
|
|
||||||
venv
|
|
||||||
|
|
||||||
*.log
|
|
||||||
*.pid
|
|
||||||
|
|
||||||
pushpin
|
|
||||||
nginx
|
|
||||||
|
|
||||||
.deploy
|
|
||||||
@ -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
|
||||||
|
|||||||
12
.gitignore
vendored
12
.gitignore
vendored
@ -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
|
|
||||||
@ -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
|
||||||
28
Makefile
28
Makefile
@ -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
|
||||||
|
|||||||
@ -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**
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
@ -66,18 +60,4 @@ 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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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>/",
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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"),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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
|
||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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 %}
|
||||||
@ -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 %}
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user