commit bf365b1204add4db97c8c3fe51c8485bd75f6712 Author: rmanach Date: Sat Sep 16 10:48:47 2023 +0200 init repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cefbd1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.ruff_cache +__pycache__ +db.sqlite3 +venv \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..788850c --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +#TODO(rmanach): add a pyproject.toml + +format: + black deployment/*.py + black mumui/*.py + +lint: + ruff deployment/*.py + ruff mumui/*.py + +migrations: + python manage.py makemigrations + python manage.py migrate + +run: + python manage.py runserver \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..197d778 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# mumui \ No newline at end of file diff --git a/deployment/__init__.py b/deployment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/deployment/admin.py b/deployment/admin.py new file mode 100644 index 0000000..4185d36 --- /dev/null +++ b/deployment/admin.py @@ -0,0 +1,3 @@ +# from django.contrib import admin + +# Register your models here. diff --git a/deployment/apps.py b/deployment/apps.py new file mode 100644 index 0000000..dc276af --- /dev/null +++ b/deployment/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class DeploymentConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "deployment" diff --git a/deployment/forms.py b/deployment/forms.py new file mode 100644 index 0000000..95835c6 --- /dev/null +++ b/deployment/forms.py @@ -0,0 +1,11 @@ +from django import forms + +from deployment.models import Type + + +class DeploymentForm(forms.Form): + name = forms.CharField() + type = forms.ChoiceField( + required=True, + choices=Type.into_choices(), + ) diff --git a/deployment/migrations/0001_initial.py b/deployment/migrations/0001_initial.py new file mode 100644 index 0000000..7da0b5a --- /dev/null +++ b/deployment/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2 on 2023-09-15 08:14 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Deployment", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.UUID("d7e9833f-e912-4640-8bf0-19e114a1136f"), + primary_key=True, + serialize=False, + ), + ), + ("name", models.TextField()), + ( + "type", + models.CharField( + choices=[("S", "Light"), ("M", "Medium"), ("L", "Heavy")], + default="S", + max_length=1, + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/deployment/migrations/0002_deployment_status_alter_deployment_id.py b/deployment/migrations/0002_deployment_status_alter_deployment_id.py new file mode 100644 index 0000000..b167b10 --- /dev/null +++ b/deployment/migrations/0002_deployment_status_alter_deployment_id.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2 on 2023-09-15 08:31 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("deployment", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="deployment", + name="status", + field=models.CharField( + choices=[ + ("PENDING", "Pending"), + ("RUNNING", "Running"), + ("SUCCESS", "Success"), + ("FAILED", "Failed"), + ], + default="PENDING", + max_length=7, + ), + ), + migrations.AlterField( + model_name="deployment", + name="id", + field=models.UUIDField( + default=uuid.UUID("7909f7f2-0ee4-45f6-b8d4-beb5df8efc73"), + primary_key=True, + serialize=False, + ), + ), + ] diff --git a/deployment/migrations/0003_alter_deployment_id_alter_deployment_status.py b/deployment/migrations/0003_alter_deployment_id_alter_deployment_status.py new file mode 100644 index 0000000..dab7bb7 --- /dev/null +++ b/deployment/migrations/0003_alter_deployment_id_alter_deployment_status.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.5 on 2023-09-16 08:16 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('deployment', '0002_deployment_status_alter_deployment_id'), + ] + + operations = [ + migrations.AlterField( + model_name='deployment', + name='id', + field=models.UUIDField(default=uuid.UUID('8584555b-51ea-46a4-aebc-f7a8ab8670a4'), primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='deployment', + name='status', + field=models.CharField(choices=[('READY', 'Ready'), ('PENDING', 'Pending'), ('RUNNING', 'Running'), ('SUCCESS', 'Success'), ('FAILED', 'Failed')], default='READY', max_length=7), + ), + ] diff --git a/deployment/migrations/0004_alter_deployment_id_alter_deployment_status_and_more.py b/deployment/migrations/0004_alter_deployment_id_alter_deployment_status_and_more.py new file mode 100644 index 0000000..12623b1 --- /dev/null +++ b/deployment/migrations/0004_alter_deployment_id_alter_deployment_status_and_more.py @@ -0,0 +1,47 @@ +# Generated by Django 4.2.5 on 2023-09-16 08:43 + +import deployment.models +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("deployment", "0003_alter_deployment_id_alter_deployment_status"), + ] + + operations = [ + migrations.AlterField( + model_name="deployment", + name="id", + field=models.UUIDField( + default=uuid.UUID("d29e958f-7b3d-43a8-bc17-a40ab4184dc6"), + primary_key=True, + serialize=False, + ), + ), + migrations.AlterField( + model_name="deployment", + name="status", + field=models.CharField( + choices=[ + ("READY", "Ready"), + ("PENDING", "Pending"), + ("RUNNING", "Running"), + ("SUCCESS", "Success"), + ("FAILED", "Failed"), + ], + default=deployment.models.Status["READY"], + max_length=7, + ), + ), + migrations.AlterField( + model_name="deployment", + name="type", + field=models.CharField( + choices=[("SLIM", "Slim"), ("MEDIUM", "Medium"), ("LARGE", "Large")], + default=deployment.models.Type["SLIM"], + max_length=6, + ), + ), + ] diff --git a/deployment/migrations/0005_alter_deployment_id.py b/deployment/migrations/0005_alter_deployment_id.py new file mode 100644 index 0000000..cf08d92 --- /dev/null +++ b/deployment/migrations/0005_alter_deployment_id.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.5 on 2023-09-16 08:43 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("deployment", "0004_alter_deployment_id_alter_deployment_status_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="deployment", + name="id", + field=models.UUIDField( + default=uuid.UUID("ec7ebcb5-420a-47c3-ba07-e8c340895865"), + primary_key=True, + serialize=False, + ), + ), + ] diff --git a/deployment/migrations/0006_alter_deployment_id_alter_deployment_status_and_more.py b/deployment/migrations/0006_alter_deployment_id_alter_deployment_status_and_more.py new file mode 100644 index 0000000..c092aaf --- /dev/null +++ b/deployment/migrations/0006_alter_deployment_id_alter_deployment_status_and_more.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2.5 on 2023-09-16 08:45 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("deployment", "0005_alter_deployment_id"), + ] + + operations = [ + migrations.AlterField( + model_name="deployment", + name="id", + field=models.UUIDField( + default=uuid.UUID("b8feb7aa-9c79-478b-ba91-df2e03f4145b"), + primary_key=True, + serialize=False, + ), + ), + migrations.AlterField( + model_name="deployment", + name="status", + field=models.CharField( + choices=[ + ("READY", "Ready"), + ("PENDING", "Pending"), + ("RUNNING", "Running"), + ("SUCCESS", "Success"), + ("FAILED", "Failed"), + ], + default="Ready", + max_length=7, + ), + ), + migrations.AlterField( + model_name="deployment", + name="type", + field=models.CharField( + choices=[("SLIM", "Slim"), ("MEDIUM", "Medium"), ("LARGE", "Large")], + default="Slim", + max_length=6, + ), + ), + ] diff --git a/deployment/migrations/__init__.py b/deployment/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/deployment/models.py b/deployment/models.py new file mode 100644 index 0000000..1a21c23 --- /dev/null +++ b/deployment/models.py @@ -0,0 +1,43 @@ +from enum import Enum +from uuid import uuid4 + + +from django.contrib.auth.models import User +from django.db import models + + +class Type(Enum): + SLIM = "Slim" + MEDIUM = "Medium" + LARGE = "Large" + + @classmethod + def into_choices(cls): + return [(s.name, s.value) for s in cls] + + +class Status(Enum): + READY = "Ready" + PENDING = "Pending" + RUNNING = "Running" + SUCCESS = "Success" + FAILED = "Failed" + + @classmethod + def into_choices(cls): + return [(s.name, s.value) for s in cls] + + +class Deployment(models.Model): + id = models.UUIDField(primary_key=True, default=uuid4()) + name = models.TextField(null=False, blank=False) + type = models.CharField( + max_length=6, choices=Type.into_choices(), default=Type.SLIM.value + ) + status = models.CharField( + max_length=7, choices=Status.into_choices(), default=Status.READY.value + ) + user = models.ForeignKey(User, on_delete=models.CASCADE) + + def __str__(self): + return f"{self.name} | {self.type} | {self.status}" diff --git a/deployment/tests.py b/deployment/tests.py new file mode 100644 index 0000000..a79ca8b --- /dev/null +++ b/deployment/tests.py @@ -0,0 +1,3 @@ +# from django.test import TestCase + +# Create your tests here. diff --git a/deployment/urls.py b/deployment/urls.py new file mode 100644 index 0000000..913056a --- /dev/null +++ b/deployment/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from deployment.views import index, create, details + +urlpatterns = [ + path("", index, name="deployment"), + path("create", create, name="deployment-create"), + path("", details, name="deployment-details"), +] diff --git a/deployment/views.py b/deployment/views.py new file mode 100644 index 0000000..03f980e --- /dev/null +++ b/deployment/views.py @@ -0,0 +1,55 @@ +from uuid import uuid4 + +from django.core.paginator import Paginator +from django.http import ( + HttpResponseRedirect, + HttpResponseServerError, + HttpResponseBadRequest, +) +from django.shortcuts import render, get_object_or_404 + +from deployment.forms import DeploymentForm +from deployment.models import Deployment + + +def index(request): + deployments = Deployment.objects.filter(user=request.user.id) + paginator = Paginator(deployments, 5) + + page_number = request.GET.get("page") + page_obj = paginator.get_page(page_number) + + return render(request, "deployment/board.html", {"page_obj": page_obj}) + + +def details(request, deployment_id): + deployment = get_object_or_404(Deployment, id=deployment_id) + + if request.method == "POST": + if deployment.status == deployment.RUNNING: + return HttpResponseBadRequest("deployment is running") + try: + deployment.delete() + except Exception as e: + return HttpResponseServerError(e) + return HttpResponseRedirect("/deployment") + + deployment = get_object_or_404(Deployment, id=deployment_id) + return render(request, "deployment/details.html", {"deployment": deployment}) + + +def create(request): + if request.method == "POST": + form = DeploymentForm(request.POST) + if form.is_valid(): + try: + Deployment.objects.create( + user=request.user, id=uuid4(), **form.cleaned_data + ) + except Exception as e: + return HttpResponseServerError(e) + return HttpResponseRedirect("/deployment") + else: + form = DeploymentForm + + return render(request, "deployment/create.html", {"form": form}) diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..7e197f2 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mumui.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/mumui/__init__.py b/mumui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mumui/asgi.py b/mumui/asgi.py new file mode 100644 index 0000000..60caa81 --- /dev/null +++ b/mumui/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for mumui project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mumui.settings") + +application = get_asgi_application() diff --git a/mumui/settings.py b/mumui/settings.py new file mode 100644 index 0000000..3666c3e --- /dev/null +++ b/mumui/settings.py @@ -0,0 +1,127 @@ +""" +Django settings for mumui project. + +Generated by 'django-admin startproject' using Django 4.2. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-_c56%%c8%g%@5(3&thxi7ku2a&wst8lik*8@l0=#)ar)s86g36" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "deployment", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "mumui.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "mumui.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +LOGIN_REDIRECT_URL = "home" +LOGOUT_REDIRECT_URL = "home" diff --git a/mumui/urls.py b/mumui/urls.py new file mode 100644 index 0000000..13f72b2 --- /dev/null +++ b/mumui/urls.py @@ -0,0 +1,26 @@ +""" +URL configuration for mumui project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.views.generic.base import TemplateView + +urlpatterns = [ + path("admin/", admin.site.urls), + path("accounts/", include("django.contrib.auth.urls")), + path("deployment/", include("deployment.urls")), + path("", TemplateView.as_view(template_name="home.html"), name="home"), +] diff --git a/mumui/wsgi.py b/mumui/wsgi.py new file mode 100644 index 0000000..dd247a1 --- /dev/null +++ b/mumui/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mumui project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mumui.settings") + +application = get_wsgi_application() diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..2776337 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,21 @@ + + + + + {% block title %}mumui{% endblock %} + + +
+ {% if user.is_authenticated or "login" in request.path %} + {% block content %} + {% endblock %} + {% if user.is_authenticated %} +

log out

+ {% endif %} + {% else %} +

You are not logged in

+ log In + {% endif %} +
+ + \ No newline at end of file diff --git a/templates/deployment/board.html b/templates/deployment/board.html new file mode 100644 index 0000000..33f5d33 --- /dev/null +++ b/templates/deployment/board.html @@ -0,0 +1,36 @@ +{% extends 'base.html' %} + +{% block title %}deployment's board{% endblock %} + +{% block content %} + {{ user.username }}'s board + {% if page_obj %} + + + {% else %} +

no deployments available

+ {% endif %} + + + +{% endblock %} \ No newline at end of file diff --git a/templates/deployment/create.html b/templates/deployment/create.html new file mode 100644 index 0000000..c781bd2 --- /dev/null +++ b/templates/deployment/create.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block title %}new deployment{% endblock %} + +{% block content %} + {{ user.username }}'s new deployment +
+ {% csrf_token %} + {{ form }} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/deployment/details.html b/templates/deployment/details.html new file mode 100644 index 0000000..48c1f9f --- /dev/null +++ b/templates/deployment/details.html @@ -0,0 +1,24 @@ +{% extends 'base.html' %} + +{% block title %}deployment details: {{ deployment.name }}{% endblock %} + +{% block content %} + + + + + + + + + + + + + +
idnametypestatus
{{ deployment.id }}{{ deployment.name }}{{ deployment.type }}{{ deployment.status }}
+
+ {% csrf_token %} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 0000000..81bb6a3 --- /dev/null +++ b/templates/home.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} + +{% block title %}home{% endblock %} + +{% block content %} + Hi {{ user.username }}! + +{% endblock %} \ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html new file mode 100644 index 0000000..31a1048 --- /dev/null +++ b/templates/registration/login.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} + +{% block title %}login{% endblock %} + +{% block content %} + {% if not user.is_authenticated %} +

log in

+
+ {% csrf_token %} + {{ form.as_p }} + +
+ {% else %} + you're already log in ! + {% endif %} +{% endblock %} \ No newline at end of file