Skip to content

Commit

Permalink
Merge pull request #4 from N5GEH/3-Work-on-projects-application
Browse files Browse the repository at this point in the history
Work on projects application
  • Loading branch information
sbanoeon authored Jul 18, 2022
2 parents 501a640 + 275bd41 commit 8749ea0
Show file tree
Hide file tree
Showing 14 changed files with 231 additions and 14 deletions.
29 changes: 23 additions & 6 deletions app/Entirety/entirety/settings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os

from pathlib import Path
from typing import List
from typing import List, Any, Optional
from mimetypes import add_type

import dj_database_url
from pydantic import BaseSettings, Field, AnyUrl, validator

from utils.generators import generate_secret_key
Expand Down Expand Up @@ -110,6 +112,7 @@ class Settings(BaseSettings):
"compressor.finders.CompressorFinder",
]


COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),)

# Default primary key field type
Expand All @@ -128,6 +131,13 @@ class Settings(BaseSettings):
},
}

# Media location
# https://docs.djangoproject.com/en/4.0/howto/static-files/#serving-files
# -uploaded-by-a-user-during-development
MEDIA_URL = "/media/"

MEDIA_ROOT = BASE_DIR / "media"

# Settings provided by environment
SECRET_KEY: str = Field(default=generate_secret_key(), env="DJANGO_SECRET_KEY")

Expand All @@ -147,12 +157,19 @@ def secret_key_not_empty(cls, v) -> str:

# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
# TODO
DATABASE_URL: str = Field(env="DATABASE_URL",
default="postgres://username:password@host:port/db")

@validator('DATABASE_URL', pre=True)
def set_url(cls, v: Optional[str]) -> Any:
if isinstance(v, str):
os.environ['DATABASE_URL'] = v
return v
else:
raise Exception

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
'default': dj_database_url.config(conn_max_age=600)
}

LOGIN_URL: str = Field(default="/oidc/authenticate", env="LOGIN_URL")
Expand Down
5 changes: 5 additions & 0 deletions app/Entirety/entirety/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include

Expand All @@ -33,3 +35,6 @@
path("examples/", include("examples.urls")),
path("oidc/", include("mozilla_django_oidc.urls")),
]

if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
19 changes: 19 additions & 0 deletions app/Entirety/projects/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from django import forms
from .models import Project


class ProjectForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProjectForm, self).__init__(*args, **kwargs)

self.helper = FormHelper(self)

self.helper.layout.append(Submit(name="save", value="Save"))

class Meta:
model = Project
fields = ['name', 'description', 'fiware_service', 'webpage_url','logo']


4 changes: 3 additions & 1 deletion app/Entirety/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ class Project(models.Model):
uuid = models.CharField(
unique=True, max_length=64, default=generate_uuid, primary_key=True
)
name = models.CharField(max_length=64)
name = models.CharField(max_length=64, unique=True)
description = models.CharField(max_length=300, null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
fiware_service = models.CharField(max_length=64, null=True)
fiware_service_path = models.CharField(max_length=1, default="/", null=True)
webpage_url = models.URLField(max_length=200, null=True)
logo = models.ImageField(upload_to='images/', null=True)

owner = models.ForeignKey(User, on_delete=models.CASCADE)
users = models.ManyToManyField(User, related_name="users", blank=True)
Expand Down
15 changes: 15 additions & 0 deletions app/Entirety/projects/templates/projects/detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends '_base.html' %}
{% load crispy_forms_tags %}

{% block content %}

<div class="container">
<h2 class="my-4">{% if project.name %} Edit {{ project.name }} {% else %} Create New Project {% endif %}</h2>
<form action="" method="post" enctype="multipart/form-data"
{% if form_submitted %}class="was-validated" {% endif %}>
{% csrf_token %}
{% crispy form %}
</form>
</div>

{% endblock %}
93 changes: 93 additions & 0 deletions app/Entirety/projects/templates/projects/index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,101 @@
{% extends '_base.html' %}
{% load static %}

{% block title %}Projects{% endblock %}

{% block content %}
<div class="container mt-5">
<div class="row">
<div class="row height d-flex justify-content-center align-items-center">
<div class="col-md-1">
<span class="input-group-btn">
<div class="row">
<a href="{% url 'projects:create' %}" class="btn btn-secondary btn-lg">
<i class="bi-plus-circle"></i>
</a>
</div>
</span>
</div>
<div class="col-md-8">
<form action="">
<div class="p-3 border border-light rounded-pill bg-light">
<div class="input-group col-md-12 border-0 shadow-none">
<input name="search" type="text" class="form-control input-lg border-light rounded-pill"
placeholder="Search projects by name"/>
<span class="input-group-btn">
<button class="btn btn-info btn-lg bg-light border-light" type="submit" value="search">
<i class="bi-search"></i>
</button>
</span>
</div>
</div>
</form>
</div>
</div>
</div>
</div>


<div class="d-flex flex-row flex-wrap">
<div class="row row-cols-1 row-cols-md-4 g-4 mt-3 mb-3">
{% for project in project_list %}
<div class="col mt-5">
<div class="card h-100">
<div class="card-header">
<h5>{{ project.name }}
<i class="bi bi-kanban"></i>
</h5>
</div>

{% if project.logo.url|length > 0 %}
<img src="{{ project.logo.url }}" class="card-img-top w-100" alt="{{ project.name }}">
{% else %}
<img src="{% static "/img/n5geh.png" %}" class="card-img-top" alt="{{ project.name }}">
{% endif %}

<div class="card-body">
<p class="card-text text-truncate">{{ project.description }}</p>
</div>

<div class="ms-3 mb-3">
<a href="{% url 'projects:update' project.uuid %}" class="btn btn-primary">Edit</a>
<button type="button" class="btn btn-primary" data-bs-toggle="modal"
data-bs-target="#deleteModal"
data-bs-url={% url 'projects:delete' project.uuid %}>
Delete
</button>
</div>

<div class="card-footer text-muted">
<small>{{ project.date_modified }}</small>
</div>
</div>
</div>
{% endfor %}
</div>
</div>


<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Delete Project</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete this project?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<form action="" method="POST" class="modal-form">
{% csrf_token %}
<button class="btn btn-primary">Delete</button>
</form>
</div>
</div>
</div>
</div>
<p>
{% if add_project %}
You are allowed to add projects
Expand Down
11 changes: 7 additions & 4 deletions app/Entirety/projects/urls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from django.contrib.auth.decorators import login_required
from django.urls import path, include
from django.urls import path

from projects.views import Index
from . import views

app_name = "projects"
urlpatterns = [
path("", login_required(Index.as_view()), name="projects"),
path("<str:project_id>/alarming/", include("alarming.urls")),
path("", login_required(views.Index.as_view()), name="index"),
path("create", views.Create.as_view(), name="create"),
path("<str:pk>/update", views.Update.as_view(), name="update"),
path("<str:pk>/delete", views.Delete.as_view(), name="delete")
]
41 changes: 40 additions & 1 deletion app/Entirety/projects/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
from django.shortcuts import render
from django.urls import reverse
from django.views.generic import View
from django.views.generic.edit import UpdateView, CreateView, \
DeleteView

# Create your views here.
from .forms import ProjectForm
from .models import Project


class Index(View):
def get(self, request):
projects = Project.objects.filter(
name__icontains=request.GET.get('search', default=""))
context = {'project_list': projects}
return render(request, 'projects/index.html', context)


class Update(UpdateView):
model = Project
template_name = 'projects/detail.html'
form_class = ProjectForm

def get_success_url(self):
return reverse("projects:index")


class Create(CreateView):
model = Project
template_name = 'projects/detail.html'
form_class = ProjectForm

def get_success_url(self):
return reverse("projects:index")


class Delete(DeleteView):
model = Project
template_name = 'projects/index.html'

def get_success_url(self):
return reverse("projects:index")
1 change: 0 additions & 1 deletion app/Entirety/projects/views/__init__.py

This file was deleted.

3 changes: 3 additions & 0 deletions app/Entirety/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ charset-normalizer==2.0.12
crispy-bootstrap5==0.6
cryptography==37.0.2
distlib==0.3.4
dj-database-url==0.5.0
Django==4.0.5
django-appconf==1.0.5
django-compressor==4.0
Expand All @@ -24,8 +25,10 @@ josepy==1.13.0
libsass==0.21.0
mozilla-django-oidc==2.0.0
nodeenv==1.7.0
Pillow==9.1.1
platformdirs==2.5.2
pre-commit==2.19.0
psycopg2==2.9.3
pycparser==2.21
pydantic==1.9.1
pyOpenSSL==22.0.0
Expand Down
10 changes: 10 additions & 0 deletions app/Entirety/static/js/modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var deleteModal = document.getElementById('deleteModal')
deleteModal.addEventListener('show.bs.modal', function (event) {
// Button that triggered the modal
var button = event.relatedTarget
// Extract info from data-bs-* attribute
var url = button.getAttribute('data-bs-url')

var modalForm = deleteModal.querySelector('.modal-form')
modalForm.attributes.getNamedItem('action').value = url
})
11 changes: 11 additions & 0 deletions app/Entirety/static/scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,14 @@
.bg-grey {
background-color: #292e34;
}

// card on hover
.card:hover{
transform:scale(1.05);
}

// card image small
.card-img-top{
height: 200px;
object-fit: fill;
}
1 change: 1 addition & 0 deletions app/Entirety/templates/_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<script src="{% static 'js/main.js' %}"></script>
<script src="{% static 'js/dialog.js' %}"></script>
<script src="{% static 'js/toast.js' %}"></script>
<script src="{% static 'js/modal.js' %}"></script>

{% block scripts %}{% endblock %}
{% endcompress %}
Expand Down
2 changes: 1 addition & 1 deletion app/Entirety/templates/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</li>
{% endif %}
<li class="nav-item d-inline-flex {% if project %}mt-auto border-top{% else %} border-bottom {% endif %}">
<a href="{% url "projects" %}" class="nav-link btn-sidebar py-md-2"
<a href="{% url "projects:index" %}" class="nav-link btn-sidebar py-md-2"
data-bs-toggle="tooltip" data-bs-placement="right" data-bs-custom-class="d-md-none"
title="Projects">
<i class="bi {% if project %}bi-arrow-left{% else %}bi-kanban{% endif %}"></i>
Expand Down

0 comments on commit 8749ea0

Please sign in to comment.