commit c602d0bf8d0e40f751da59b245403fa15e752f7a Author: Lucas F. Date: Wed Feb 7 09:40:06 2024 -0300 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6e00c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +venv +.venv +.env +*.sqlite3 +media +*__pycache__ +.idea +*.code-workspace +.report.json +report.json +.vscode diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2c4d54a --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) Lucas F. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d32027f --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +.DEFAULT_GOAL = default +SCRIPT = contrib/scripts/make_scripts.sh + +## @ env +.PHONY: env +env: ## creates a .env file + @./${SCRIPT} make_env_file + +## @ task +.PHONY: check run shell_plus clear_migrations show_migrations migrations migrate elements +check: ## same as manage.py check + @./${SCRIPT} check + +run: ## same as manage.py run server + @./${SCRIPT} run + +shell_plus: ## same as .manage.py shell_plus + @./${SCRIPT} shell_plus + +clear_migrations: ## same as manage.py showmigrations + @./${SCRIPT} show_migrations + +show_migrations: ## same as manage.py showmigrations + @./${SCRIPT} show_migrations + +migrations: ## same as manage.py makemigrations + @./${SCRIPT} migrations + +migrate: ## same as manage.py migrate + @./${SCRIPT} migrate + +elements: ## create initial app elements + @./${SCRIPT} elements + +## @ help +.PHONY: help +help: ## display all make commands + @./${SCRIPT} help $(MAKEFILE_LIST) + +default: help diff --git a/README.md b/README.md new file mode 100644 index 0000000..1aa200c --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# Form User + +É um exemplo de aplicação Django para criação de modelo, tendo em vista salvar dois modelos ao mesmo tempo, +sendo que um deles possui relação do tipo muitos para muitos. + + +## Instalação + +via `pip` + +```bash +git clone https://git.lucasf.dev/public/form_user.git +cd form_user +python -m venv .venv +. ./.venv/bin/activate +pip install -r requirements.txt +``` + + +via `poetry` + +```bash +git clone https://git.lucasf.dev/public/form_user.git +cd form_user +poetry shell +poetry install +``` + + +## Criando arquivo .env + +```bash +make env +``` + +## Criando elementos para aplicação + +primeiro informe no arquivo `.env` gerado os valores para as seguintes variáveis: + +ADMIN_USERNAME +ADMIN_EMAIL +ADMIN_PASSWORD + +```bash +make elements +``` + +## Iniciar a aplicação + +```bash +make run +``` + diff --git a/contrib/scripts/make_scripts.sh b/contrib/scripts/make_scripts.sh new file mode 100755 index 0000000..de901fd --- /dev/null +++ b/contrib/scripts/make_scripts.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash + +HERE="$(cd "$(dirname "$0")" && pwd)" +BASEDIR="$(cd "$(dirname "$1")" && pwd)" +CHARS="abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)" +for ((i=0;i<${#CHARS};i++)); do ARRAY[$i]="${CHARS:i:1}"; done +MSG_SUCCESS="DONE!" +POETRY=0 +PYTHON=0 + +key_gen() { + for ((c=1; c<=50; c++)); do + KEY="$KEY${ARRAY[$((RANDOM % 50))]}" + done + echo $KEY +} + +make_env_file() { + if [[ ! -f ".env" ]]; then + ENV="SECRET_KEY='$(key_gen)'\n + ALLOWED_HOSTS=localhost, 10.0.2.2, 127.0.0.1\n + DEBUG=True\n\n + #DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5433/db\n\n + ADMIN_USERNAME=\n + ADMIN_EMAIL=\n + ADMIN_PASSWORD=\n\n + EMAIL_HOST=\n + EMAIL_PORT=\n + EMAIL_HOST_USER=\n + EMAIL_HOST_PASSWORD=\n + EMAIL_USE_TLS=True\n + DEFAULT_FROM_EMAIL= + " + + $(echo -e $ENV | sed -e 's/^[ \t]*//' > .env) + echo "ENV FILE - $MSG_SUCCESS" + fi +} + +verify_poetry() { + if command -v poetry &> /dev/null; then + POETRY=1 + fi +} + +verify_python() { + if command -v python3 &> /dev/null; then + PYTHON=1 + fi +} + +venv_name() { + if [[ -d "$BASEDIR/.venv" ]]; then + echo ".venv" + fi + if [[ -d "$BASEDIR/venv" ]]; then + echo "venv" + fi +} + +python_name() { + if [[ PYTHON -eq 1 ]]; then + echo "python3" + else + echo "python" + fi +} + +help() { + awk 'BEGIN {FS="## @ "; print "Usage: make";} /^## @ / { printf "\033[31m\n" substr($1, 5) "\n";} {FS=" ## ";} /^[a-zA-Z_-]+:.*? ##/ { print "\033[33m -", $1 "\033[37m", $2}' $ARG +} + +run() { + $(venv_name)/bin/$(python_name) manage.py runserver 0.0.0.0:8000 +} + +shell_plus() { + $(venv_name)/bin/$(python_name) manage.py shell_plus +} + +check() { + $(venv_name)/bin/$(python_name) manage.py check + IS_OK=$? +} + +show_migrations() { + $(venv_name)/bin/$(python_name) manage.py showmigrations +} + +migrations() { + $(venv_name)/bin/$(python_name) manage.py makemigrations +} + +migrate() { + $(venv_name)/bin/$(python_name) manage.py migrate +} + +check() { + $(venv_name)/bin/$(python_name) manage.py check +} + +elements() { + $(venv_name)/bin/$(python_name) manage.py elements +} + +clear_migrations() { + find $BASEDIR -path '*/migrations/*.py' -not -name '__init__.py' -not -path '*/.venv/*' -delete + find $BASEDIR -path '*/migrations/*.pyc' -not -name '__init__.py' -not -path '*/.venv/*' -delete + if [[ -f $BASEDIR/media/ ]]; then + rm $BASEDIR/media/* + fi + if [[ -f db.sqlite3 ]];then + rm db.sqlite3 + fi + podman pod rm -f cq_pod && + podman volume prune +} + +verify_python +verify_poetry +ARG=$2 +$1 diff --git a/form_user/__init__.py b/form_user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/form_user/apps/__init__.py b/form_user/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/form_user/apps/contas/__init__.py b/form_user/apps/contas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/form_user/apps/contas/admin.py b/form_user/apps/contas/admin.py new file mode 100644 index 0000000..7d111bb --- /dev/null +++ b/form_user/apps/contas/admin.py @@ -0,0 +1,64 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.forms import UserCreationForm + +from .forms import UserAdminForm +from .models import CustomUser, TagUnidade, Unidade, UsuarioPermissaoUnidadeTag + + +class UserAdmin(BaseUserAdmin): + add_form = UserCreationForm + add_fieldsets = ( + ( + None, + { + "classes": ("wide",), + "fields": ( + "username", + "email", + "password1", + "password2", + "is_active", + ), + }, + ), + ) + form = UserAdminForm + fieldsets = ( + (None, {"fields": ("username", "email")}), + ( + "Informações Básicas", + { + "fields": ( + "first_name", + "last_login", + ) + }, + ), + ( + "Permissões", + { + "fields": ( + "is_active", + "is_staff", + "is_superuser", + "groups", + "user_permissions", + ) + }, + ), + ) + list_display = [ + "username", + "first_name", + "email", + "is_active", + "is_staff", + "date_joined", + ] + + +admin.site.register(CustomUser, UserAdmin) +admin.site.register(UsuarioPermissaoUnidadeTag) +admin.site.register(TagUnidade) +admin.site.register(Unidade) diff --git a/form_user/apps/contas/apps.py b/form_user/apps/contas/apps.py new file mode 100644 index 0000000..ecc21a0 --- /dev/null +++ b/form_user/apps/contas/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class ContasConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "contas" + default = False diff --git a/form_user/apps/contas/forms.py b/form_user/apps/contas/forms.py new file mode 100644 index 0000000..a3e4214 --- /dev/null +++ b/form_user/apps/contas/forms.py @@ -0,0 +1,28 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm + +from form_user.apps.contas.models import CustomUser, UsuarioPermissaoUnidadeTag + + +class UserAdminForm(forms.ModelForm): + class Meta: + model = CustomUser + fields = UserCreationForm.Meta.fields + ( + "username", + "email", + "first_name", + "is_active", + "is_staff", + ) + + +class PermissaoForm(forms.ModelForm): + class Meta: + model = UsuarioPermissaoUnidadeTag + fields = ["tags", "unidades"] + + +class NewUserForm(forms.ModelForm): + class Meta: + model = CustomUser + fields = ["username"] diff --git a/form_user/apps/contas/management/commands/elements.py b/form_user/apps/contas/management/commands/elements.py new file mode 100644 index 0000000..730b89e --- /dev/null +++ b/form_user/apps/contas/management/commands/elements.py @@ -0,0 +1,33 @@ +from decouple import config +from django.core.management.base import BaseCommand +from django.utils.translation import gettext_lazy as _ + +from form_user.apps.contas.models import CustomUser + + +class AppException(Exception, BaseCommand): + def __init__(self, exception): + print( + BaseCommand().stdout.write( + BaseCommand().style.NOTICE(f"Error: {exception}") + ) + ) + + +class Command(BaseCommand): + help = _("Creates initial information for application") + su_created = False + + def handle(self, *args, **options): + if not CustomUser.objects.filter(username=config("ADMIN_USERNAME")): + su = CustomUser.objects.create_superuser( + username=config("ADMIN_USERNAME"), + email=config("ADMIN_EMAIL"), + password=config("ADMIN_PASSWORD"), + is_active=True, + is_staff=True, + ) + if su: + self.stdout.write(self.style.SUCCESS(_("Superuser created!"))) + else: + self.stdout.write(self.style.NOTICE(_("Superuser already exists!"))) diff --git a/form_user/apps/contas/managers.py b/form_user/apps/contas/managers.py new file mode 100644 index 0000000..ce6ee57 --- /dev/null +++ b/form_user/apps/contas/managers.py @@ -0,0 +1,7 @@ +from django.contrib.auth.models import UserManager +from django.db.models import Q + + +class CustomUserManager(UserManager): + def all(self): + return self.get_queryset().filter(~Q(username="admin")) diff --git a/form_user/apps/contas/migrations/0001_initial.py b/form_user/apps/contas/migrations/0001_initial.py new file mode 100644 index 0000000..303c1f1 --- /dev/null +++ b/form_user/apps/contas/migrations/0001_initial.py @@ -0,0 +1,214 @@ +# Generated by Django 5.0.2 on 2024-02-06 18:32 + +import django.contrib.auth.validators +import django.db.models.deletion +import django.utils.timezone +import form_user.apps.contas.managers +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ] + + operations = [ + migrations.CreateModel( + name="TagUnidade", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("nome", models.CharField(max_length=50, verbose_name="Nome")), + ], + ), + migrations.CreateModel( + name="Unidade", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("nome", models.CharField(max_length=50, verbose_name="Nome")), + ], + ), + migrations.CreateModel( + name="CustomUser", + fields=[ + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + verbose_name="Identifier", + ), + ), + ( + "is_staff", + models.BooleanField(default=False, verbose_name="staff status"), + ), + ( + "is_active", + models.BooleanField(default=False, verbose_name="active"), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.permission", + verbose_name="user permissions", + ), + ), + ( + "usuario_agrupador", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="agrupador", + to=settings.AUTH_USER_MODEL, + verbose_name="Usuário Agrupador", + ), + ), + ], + options={ + "verbose_name": "Usuário", + "verbose_name_plural": "Usuários", + }, + managers=[ + ("objects", form_user.apps.contas.managers.CustomUserManager()), + ], + ), + migrations.CreateModel( + name="UsuarioPermissaoUnidadeTag", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "tags", + models.ManyToManyField(to="contas.tagunidade", verbose_name="Tags"), + ), + ( + "unidades", + models.ManyToManyField( + to="contas.unidade", verbose_name="Unidades" + ), + ), + ( + "usuario", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="per_custom_user", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "usuario_inclusao", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="usuario_inclusao", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "verbose_name": "Permissão de Acesso Tag e Unidade", + "verbose_name_plural": "Permissões de Acesso Tags e Unidades", + }, + ), + ] diff --git a/form_user/apps/contas/migrations/0002_alter_customuser_usuario_agrupador.py b/form_user/apps/contas/migrations/0002_alter_customuser_usuario_agrupador.py new file mode 100644 index 0000000..42f7535 --- /dev/null +++ b/form_user/apps/contas/migrations/0002_alter_customuser_usuario_agrupador.py @@ -0,0 +1,27 @@ +# Generated by Django 5.0.2 on 2024-02-06 18:35 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("contas", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="customuser", + name="usuario_agrupador", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="agrupador", + to=settings.AUTH_USER_MODEL, + verbose_name="Usuário Agrupador", + ), + ), + ] diff --git a/form_user/apps/contas/migrations/__init__.py b/form_user/apps/contas/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/form_user/apps/contas/models.py b/form_user/apps/contas/models.py new file mode 100644 index 0000000..e686d43 --- /dev/null +++ b/form_user/apps/contas/models.py @@ -0,0 +1,79 @@ +import uuid + +from django.contrib.auth.models import AbstractUser +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from .managers import CustomUserManager + + +class TagUnidade(models.Model): + nome = models.CharField("Nome", max_length=50) + + def __str__(self): + return self.nome + + +class Unidade(models.Model): + nome = models.CharField("Nome", max_length=50) + + def __str__(self): + return self.nome + + +class CustomUser(AbstractUser): + id = models.UUIDField( + _("Identifier"), primary_key=True, default=uuid.uuid4, editable=False + ) + is_staff = models.BooleanField(_("staff status"), default=False) + is_active = models.BooleanField(_("active"), default=False) + + usuario_agrupador = models.ForeignKey( + "self", + on_delete=models.CASCADE, + verbose_name="Usuário Agrupador", + related_name="agrupador", + null=True, + blank=True, + ) + + EMAIL_FIELD = "email" + USERNAME_FIELD = "username" + REQUIRED_FIELDS = ["email"] + + objects = CustomUserManager() + + class Meta: + verbose_name = "Usuário" + verbose_name_plural = "Usuários" + + def __str__(self): + return self.first_name or self.username + + +class UsuarioPermissaoUnidadeTag(models.Model): + usuario = models.ForeignKey( + CustomUser, + on_delete=models.CASCADE, + related_name="per_custom_user", + null=True, + blank=True, + ) + + tags = models.ManyToManyField(TagUnidade, verbose_name="Tags") + unidades = models.ManyToManyField(Unidade, verbose_name="Unidades") + + usuario_inclusao = models.ForeignKey( + CustomUser, + on_delete=models.CASCADE, + related_name="usuario_inclusao", + null=True, + blank=True, + ) + + def __str__(self): + return self.usuario.username + + class Meta: + verbose_name = "Permissão de Acesso Tag e Unidade" + verbose_name_plural = "Permissões de Acesso Tags e Unidades" diff --git a/form_user/apps/contas/static/contas/css/main.css b/form_user/apps/contas/static/contas/css/main.css new file mode 100644 index 0000000..ea941d8 --- /dev/null +++ b/form_user/apps/contas/static/contas/css/main.css @@ -0,0 +1,15 @@ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + + +body { + display: grid; + place-content: center; + align-items: center; + height: 100vh; +} diff --git a/form_user/apps/contas/templates/contas/base.html b/form_user/apps/contas/templates/contas/base.html new file mode 100644 index 0000000..41d2d49 --- /dev/null +++ b/form_user/apps/contas/templates/contas/base.html @@ -0,0 +1,13 @@ +{% load static %} + + + + + + + Form Test + + + {% block content %}{% endblock content %} + + diff --git a/form_user/apps/contas/templates/contas/form.html b/form_user/apps/contas/templates/contas/form.html new file mode 100644 index 0000000..ce7a411 --- /dev/null +++ b/form_user/apps/contas/templates/contas/form.html @@ -0,0 +1,13 @@ +{% extends "contas/base.html" %} + +{% load static %} + +{% block content %} + Voltar +
+ {% csrf_token %} + {{ form.as_p }} + {{ form_permissao.as_p }} + +
+{% endblock content %} diff --git a/form_user/apps/contas/templates/contas/index.html b/form_user/apps/contas/templates/contas/index.html new file mode 100644 index 0000000..ee8900f --- /dev/null +++ b/form_user/apps/contas/templates/contas/index.html @@ -0,0 +1,13 @@ +{% extends "contas/base.html" %} + +{% load static %} + +{% block content %} + Novo Usuário
+ +{% endblock content %} + diff --git a/form_user/apps/contas/tests.py b/form_user/apps/contas/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/form_user/apps/contas/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/form_user/apps/contas/urls.py b/form_user/apps/contas/urls.py new file mode 100644 index 0000000..4022f0e --- /dev/null +++ b/form_user/apps/contas/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from . import views + +app_name = "contas" + +urlpatterns = [ + path("", views.Index.as_view(), name="index"), + path("novo/", views.Novo.as_view(), name="novo"), + path("editar//", views.Editar.as_view(), name="editar"), +] diff --git a/form_user/apps/contas/views.py b/form_user/apps/contas/views.py new file mode 100644 index 0000000..8dda1e5 --- /dev/null +++ b/form_user/apps/contas/views.py @@ -0,0 +1,55 @@ +from django.db import transaction +from django.http import HttpResponseRedirect +from django.urls import reverse_lazy +from django.views.generic import CreateView, ListView, UpdateView + +from form_user.apps.contas.models import CustomUser + +from . import forms + + +class Common: + model = CustomUser + template_name = "contas/form.html" + form_class = forms.NewUserForm + success_url = reverse_lazy("contas:index") + + +class Index(Common, ListView): + template_name = "contas/index.html" + paginate_by = 10 + + +class NovoEditar(Common): + def form_valid(self, form): + form_permissao = forms.PermissaoForm(self.request.POST) + form_permissao.full_clean() + + if not form_permissao.is_valid(): + context = self.get_context_data(form=form) + context.update(form_permissao=form_permissao) + return self.render_to_response(context) + + with transaction.atomic(): + ob = form.save() + form_permissao.instance.usuario = ob + form_permissao.instance.usuario_inclusao = ob + form_permissao.save() + + return HttpResponseRedirect(self.success_url) + + +class Novo(NovoEditar, CreateView): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["form_permissao"] = forms.PermissaoForm() + return context + + +class Editar(NovoEditar, UpdateView): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["form_permissao"] = forms.PermissaoForm( + instance=self.object.per_custom_user.first() + ) + return context diff --git a/form_user/asgi.py b/form_user/asgi.py new file mode 100644 index 0000000..86dc222 --- /dev/null +++ b/form_user/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for form_user 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/5.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'form_user.settings') + +application = get_asgi_application() diff --git a/form_user/settings.py b/form_user/settings.py new file mode 100644 index 0000000..4d52a5f --- /dev/null +++ b/form_user/settings.py @@ -0,0 +1,138 @@ +""" +Django settings for form_user project. + +Generated by 'django-admin startproject' using Django 5.0.2. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.0/ref/settings/ +""" + +import os +from pathlib import Path + +from decouple import Csv, config +from dj_database_url import parse as dburl + +# 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/5.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = config("SECRET_KEY") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = config("DEBUG", default=False, cast=bool) + +ALLOWED_HOSTS = config("ALLOWED_HOSTS", cast=Csv()) + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django_extensions", + "form_user.apps.contas", +] + +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 = "form_user.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": ["templates", 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 = "form_user.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/5.0/ref/settings/#databases + +default_dburl = "sqlite:///" + os.path.join(BASE_DIR, "db.sqlite3") + +DATABASES = { + "default": config("DATABASE_URL", default=default_dburl, cast=dburl), +} + + +# Password validation +# https://docs.djangoproject.com/en/5.0/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/5.0/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/5.0/howto/static-files/ +STATIC_URL = "static/" + +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "staticfiles"), +] + +MEDIA_URL = "/media/" + +MEDIA_ROOT = os.path.join(BASE_DIR, "media") + +STATIC_ROOT = os.path.join(BASE_DIR, "static/") + +# Default primary key field type +# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +AUTH_USER_MODEL = "contas.CustomUser" diff --git a/form_user/urls.py b/form_user/urls.py new file mode 100644 index 0000000..642482c --- /dev/null +++ b/form_user/urls.py @@ -0,0 +1,24 @@ +""" +URL configuration for form_user project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.0/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 include, path + +urlpatterns = [ + path("admin/", admin.site.urls), + path("", include("form_user.apps.contas.urls", namespace="contas")), +] diff --git a/form_user/wsgi.py b/form_user/wsgi.py new file mode 100644 index 0000000..7c31fa8 --- /dev/null +++ b/form_user/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for form_user 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/5.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'form_user.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..a966a95 --- /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', 'form_user.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/poetry.lock b/poetry.lock new file mode 100644 index 0000000..404e633 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,118 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.7.2" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.7" +files = [ + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, +] + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "dj-database-url" +version = "2.1.0" +description = "Use Database URLs in your Django Application." +optional = false +python-versions = "*" +files = [ + {file = "dj-database-url-2.1.0.tar.gz", hash = "sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f"}, + {file = "dj_database_url-2.1.0-py3-none-any.whl", hash = "sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0"}, +] + +[package.dependencies] +Django = ">=3.2" +typing-extensions = ">=3.10.0.0" + +[[package]] +name = "django" +version = "5.0.2" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.10" +files = [ + {file = "Django-5.0.2-py3-none-any.whl", hash = "sha256:56ab63a105e8bb06ee67381d7b65fe6774f057e41a8bab06c8020c8882d8ecd4"}, + {file = "Django-5.0.2.tar.gz", hash = "sha256:b5bb1d11b2518a5f91372a282f24662f58f66749666b0a286ab057029f728080"}, +] + +[package.dependencies] +asgiref = ">=3.7.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-extensions" +version = "3.2.3" +description = "Extensions for Django" +optional = false +python-versions = ">=3.6" +files = [ + {file = "django-extensions-3.2.3.tar.gz", hash = "sha256:44d27919d04e23b3f40231c4ab7af4e61ce832ef46d610cc650d53e68328410a"}, + {file = "django_extensions-3.2.3-py3-none-any.whl", hash = "sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401"}, +] + +[package.dependencies] +Django = ">=3.2" + +[[package]] +name = "python-decouple" +version = "3.8" +description = "Strict separation of settings from code." +optional = false +python-versions = "*" +files = [ + {file = "python-decouple-3.8.tar.gz", hash = "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f"}, + {file = "python_decouple-3.8-py3-none-any.whl", hash = "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66"}, +] + +[[package]] +name = "sqlparse" +version = "0.4.4" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "tzdata" +version = "2023.4" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, + {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "3f3d4eb61266813806f194403d47bbd1801f62ca247a7ef3dc226a606fe9327f" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8405ebc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "form-user" +version = "0.1.0" +description = "" +authors = ["Lucas F. "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +django = "^5.0.2" +python-decouple = "^3.8" +django-extensions = "^3.2.3" +dj-database-url = "^2.1.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..31d09ce --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +asgiref==3.7.2 ; python_version >= "3.11" and python_version < "4.0" +dj-database-url==2.1.0 ; python_version >= "3.11" and python_version < "4.0" +django-extensions==3.2.3 ; python_version >= "3.11" and python_version < "4.0" +django==5.0.2 ; python_version >= "3.11" and python_version < "4.0" +python-decouple==3.8 ; python_version >= "3.11" and python_version < "4.0" +sqlparse==0.4.4 ; python_version >= "3.11" and python_version < "4.0" +typing-extensions==4.9.0 ; python_version >= "3.11" and python_version < "4.0" +tzdata==2023.4 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "win32"