/staticfiles/
17 |
18 | ### Django.Python Stack ###
19 | # Byte-compiled / optimized / DLL files
20 | *.py[cod]
21 | *$py.class
22 |
23 | # C extensions
24 | *.so
25 |
26 | # Distribution / packaging
27 | .Python
28 | build/
29 | develop-eggs/
30 | dist/
31 | downloads/
32 | eggs/
33 | .eggs/
34 | lib/
35 | lib64/
36 | parts/
37 | sdist/
38 | var/
39 | wheels/
40 | pip-wheel-metadata/
41 | share/python-wheels/
42 | *.egg-info/
43 | .installed.cfg
44 | *.egg
45 | MANIFEST
46 |
47 | # PyInstaller
48 | # Usually these files are written by a python script from a template
49 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
50 | *.manifest
51 | *.spec
52 |
53 | # Installer logs
54 | pip-log.txt
55 | pip-delete-this-directory.txt
56 |
57 | # Unit test / coverage reports
58 | htmlcov/
59 | .tox/
60 | .nox/
61 | .coverage
62 | .coverage.*
63 | .cache
64 | nosetests.xml
65 | coverage.xml
66 | *.cover
67 | .hypothesis/
68 | .pytest_cache/
69 |
70 | # Translations
71 | *.mo
72 |
73 | # Django stuff:
74 |
75 | # Flask stuff:
76 | instance/
77 | .webassets-cache
78 |
79 | # Scrapy stuff:
80 | .scrapy
81 |
82 | # Sphinx documentation
83 | docs/_build/
84 |
85 | # PyBuilder
86 | target/
87 |
88 | # Jupyter Notebook
89 | .ipynb_checkpoints
90 |
91 | # IPython
92 | profile_default/
93 | ipython_config.py
94 |
95 | # pyenv
96 | .python-version
97 |
98 | # pipenv
99 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
100 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
101 | # having no cross-platform support, pipenv may install dependencies that don’t work, or not
102 | # install all needed dependencies.
103 | #Pipfile.lock
104 |
105 | # celery beat schedule file
106 | celerybeat-schedule
107 |
108 | # SageMath parsed files
109 | *.sage.py
110 |
111 | # Environments
112 | .env
113 | .venv
114 | env/
115 | venv/
116 | ENV/
117 | env.bak/
118 | venv.bak/
119 |
120 | # Spyder project settings
121 | .spyderproject
122 | .spyproject
123 |
124 | # Rope project settings
125 | .ropeproject
126 |
127 | # mkdocs documentation
128 | /site
129 |
130 | # mypy
131 | .mypy_cache/
132 | .dmypy.json
133 | dmypy.json
134 | .vscode/
135 | # Pyre type checker
136 | .pyre/
137 |
138 | # End of https://www.gitignore.io/api/django
139 |
--------------------------------------------------------------------------------
/templates/libro/autor/autor_formset.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 | {% load staticfiles %}
3 | {% block titulo %}
4 | Biblioteca.dev | Formset Autor
5 | {% endblock titulo %}
6 | {% block extra_css %}
7 |
8 | {% endblock extra_css %}
9 | {% block body %}
10 |
11 |
35 |
36 | {% endblock body %}
37 | {% block extrajs %}
38 |
67 | {% endblock extrajs %}
--------------------------------------------------------------------------------
/templates/libro/detalle_libro_disponible.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 | {% load staticfiles %}
3 | {% block titulo %}
4 | Biblioteca.dev | {{ object }}
5 | {% endblock titulo %}
6 | {% block extra_css %}
7 | {% endblock extra_css %}
8 | {% block body %}
9 |
10 |
48 |
49 |
50 |
51 | {% endblock body %}
52 | {% block extrajs %}
53 |
74 | {% endblock extrajs %}
--------------------------------------------------------------------------------
/apps/usuario/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2021-07-18 18:23
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ('auth', '0011_update_proxy_permissions'),
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='Rol',
18 | fields=[
19 | ('id', models.AutoField(primary_key=True, serialize=False)),
20 | ('rol', models.CharField(max_length=50, unique=True, verbose_name='Rol')),
21 | ],
22 | options={
23 | 'verbose_name': 'Rol',
24 | 'verbose_name_plural': 'Rols',
25 | },
26 | ),
27 | migrations.CreateModel(
28 | name='Usuario',
29 | fields=[
30 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
31 | ('password', models.CharField(max_length=128, verbose_name='password')),
32 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
33 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
34 | ('username', models.CharField(max_length=100, unique=True, verbose_name='Nombre de usuario')),
35 | ('email', models.EmailField(max_length=254, unique=True, verbose_name='Correo Electrónico')),
36 | ('nombres', models.CharField(blank=True, max_length=200, null=True, verbose_name='Nombres')),
37 | ('apellidos', models.CharField(blank=True, max_length=200, null=True, verbose_name='Apellidos')),
38 | ('imagen', models.ImageField(blank=True, max_length=200, null=True, upload_to='perfil/', verbose_name='Imagen de Perfil')),
39 | ('is_active', models.BooleanField(default=True)),
40 | ('is_staff', models.BooleanField(default=False)),
41 | ('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')),
42 | ('rol', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='usuario.Rol')),
43 | ('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')),
44 | ],
45 | options={
46 | 'permissions': [('permiso_desde_codigo', 'Este es un permiso creado desde código'), ('segundo_permiso_codigo', 'Segundo permiso creado desde codigo')],
47 | },
48 | ),
49 | ]
50 |
--------------------------------------------------------------------------------
/apps/libro/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2021-07-18 18:23
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Autor',
17 | fields=[
18 | ('id', models.AutoField(primary_key=True, serialize=False)),
19 | ('nombre', models.CharField(max_length=200)),
20 | ('apellidos', models.CharField(max_length=220)),
21 | ('nacionalidad', models.CharField(max_length=100)),
22 | ('descripcion', models.TextField()),
23 | ('estado', models.BooleanField(default=True, verbose_name='Estado')),
24 | ('fecha_creacion', models.DateField(auto_now=True, verbose_name='Fecha de creación')),
25 | ],
26 | options={
27 | 'verbose_name': 'Autor',
28 | 'verbose_name_plural': 'Autores',
29 | 'ordering': ['nombre'],
30 | },
31 | ),
32 | migrations.CreateModel(
33 | name='Libro',
34 | fields=[
35 | ('id', models.AutoField(primary_key=True, serialize=False)),
36 | ('titulo', models.CharField(max_length=255, verbose_name='Título')),
37 | ('fecha_publicacion', models.DateField(verbose_name='Fecha de publicación')),
38 | ('descripcion', models.TextField(blank=True, null=True, verbose_name='Descripción')),
39 | ('cantidad', models.PositiveIntegerField(default=1, verbose_name='Cantidad o Stock')),
40 | ('imagen', models.ImageField(blank=True, max_length=255, null=True, upload_to='libros/', verbose_name='Imagen')),
41 | ('fecha_creacion', models.DateField(auto_now=True, verbose_name='Fecha de creación')),
42 | ('estado', models.BooleanField(default=True, verbose_name='Estado')),
43 | ],
44 | options={
45 | 'verbose_name': 'Libro',
46 | 'verbose_name_plural': 'Libros',
47 | 'ordering': ['titulo'],
48 | },
49 | ),
50 | migrations.CreateModel(
51 | name='Reserva',
52 | fields=[
53 | ('id', models.AutoField(primary_key=True, serialize=False)),
54 | ('cantidad_dias', models.SmallIntegerField(default=7, verbose_name='Cantidad de Dias a Reservar')),
55 | ('fecha_creacion', models.DateField(auto_now_add=True, verbose_name='Fecha de creación')),
56 | ('fecha_vencimiento', models.DateField(blank=True, null=True, verbose_name='Fecha de vencimiento de la reserva')),
57 | ('estado', models.BooleanField(default=True, verbose_name='Estado')),
58 | ('libro', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='libro.Libro')),
59 | ],
60 | options={
61 | 'verbose_name': 'Reserva',
62 | 'verbose_name_plural': 'Reservas',
63 | },
64 | ),
65 | ]
66 |
--------------------------------------------------------------------------------
/apps/libro/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from django.core.exceptions import ValidationError
3 | from .models import Autor,Libro,Reserva
4 |
5 | class AutorForm(forms.ModelForm):
6 | class Meta:
7 | model = Autor
8 | fields = ['nombre','apellidos']
9 | labels = {
10 | 'nombre': 'Nombre del autor',
11 | 'apellidos': 'Apellidos del autor',
12 | 'nacionalidad': 'Nacionalidad del autor',
13 | 'descripcion': 'Pequeña descripción',
14 | }
15 | widgets = {
16 | 'nombre': forms.TextInput(
17 | attrs = {
18 | 'class':'form-control',
19 | 'placeholder':'Ingrese el nombre del autor'
20 | }
21 | ),
22 | 'apellidos': forms.TextInput(
23 | attrs = {
24 | 'class':'form-control',
25 | 'placeholder':'Ingrese los apellidos del autor'
26 | }
27 | ),
28 | 'nacionalidad':forms.TextInput(
29 | attrs = {
30 | 'class':'form-control',
31 | 'placeholder':'Ingrese una nacionalidad para el autor'
32 | }
33 | ),
34 | 'descripcion': forms.Textarea(
35 | attrs = {
36 | 'class':'form-control',
37 | 'placeholder': 'Ingrese una pequeña descripcion para el autor'
38 | }
39 | )
40 | }
41 |
42 | class ReservaForm(forms.ModelForm):
43 | def __init__(self, *args, **kwargs):
44 | super().__init__(*args, **kwargs)
45 | #self.fields['libro'].queryset = Libro.objects.filter(estado = True,cantidad__gte = 1)
46 |
47 | class Meta:
48 | model = Reserva
49 | fields = '__all__'
50 |
51 | def clean_libro(self):
52 | libro = self.cleaned_data['libro']
53 | if libro.cantidad < 1:
54 | raise ValidationError('No se puede reservar este libro, deben existir unidades disponibles.')
55 |
56 | return libro
57 |
58 | class LibroForm(forms.ModelForm):
59 |
60 | def __init__(self, *args, **kwargs):
61 | super().__init__(*args, **kwargs)
62 | self.fields['autor_id'].queryset = Autor.objects.filter(estado = True)
63 |
64 |
65 | class Meta:
66 | model = Libro
67 | fields = ('titulo','autor','fecha_publicacion','descripcion','imagen','cantidad')
68 | label = {
69 | 'titulo':'Título del libro',
70 | 'autor_id': 'Autor(es) del Libro',
71 | 'fecha_publicacion': 'Fecha de Publciación del Libro'
72 | }
73 | widgets = {
74 | 'titulo': forms.TextInput(
75 | attrs = {
76 | 'class': 'form-control',
77 | 'placeholder': 'Ingrese título de libro'
78 | }
79 | ),
80 | 'autor_id': forms.SelectMultiple(
81 | attrs = {
82 | 'class':'form-control'
83 | }
84 | ),
85 | 'fecha_publicacion': forms.SelectDateWidget(
86 | attrs = {
87 | 'class': 'form-control'
88 | }
89 | )
90 | }
91 |
--------------------------------------------------------------------------------
/templates/login.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
5 |
6 |
7 | Inicio de Sesión | BIBLIOTECA.DEV
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/biblioteca/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for biblioteca project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.0.6.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.0/ref/settings/
11 | """
12 |
13 | import os
14 | from django.urls import reverse_lazy
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = 'dj&!t6j@th%ecbu%ud70q$)!3&!n8@c_9m%o5(9+iy$p35=c3^'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'import_export',
41 | 'apps.libro',
42 | 'apps.usuario',
43 | ]
44 |
45 | MIDDLEWARE = [
46 | 'querycount.middleware.QueryCountMiddleware',
47 | 'apps.usuario.middleware.PruebaMiddleware',
48 | 'django.middleware.security.SecurityMiddleware',
49 | 'django.contrib.sessions.middleware.SessionMiddleware',
50 | 'django.middleware.common.CommonMiddleware',
51 | 'django.middleware.csrf.CsrfViewMiddleware',
52 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
53 | 'django.contrib.messages.middleware.MessageMiddleware',
54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
55 | ]
56 |
57 | ROOT_URLCONF = 'biblioteca.urls'
58 |
59 | TEMPLATES = [
60 | {
61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
62 | 'DIRS': ['templates'],
63 | 'APP_DIRS': True,
64 | 'OPTIONS': {
65 | 'context_processors': [
66 | 'django.template.context_processors.debug',
67 | 'django.template.context_processors.request',
68 | 'django.contrib.auth.context_processors.auth',
69 | 'django.contrib.messages.context_processors.messages',
70 | ],
71 | },
72 | },
73 | ]
74 |
75 | WSGI_APPLICATION = 'biblioteca.wsgi.application'
76 |
77 |
78 | # Database
79 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
80 |
81 | DATABASES = {
82 | 'default': {
83 | 'ENGINE': 'django.db.backends.sqlite3',
84 | 'NAME': 'db.sqlite3',
85 | }
86 | }
87 |
88 |
89 | # Password validation
90 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
91 |
92 | AUTH_PASSWORD_VALIDATORS = [
93 | {
94 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
95 | },
96 | {
97 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
98 | },
99 | {
100 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
101 | },
102 | {
103 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
104 | },
105 | ]
106 |
107 | AUTH_USER_MODEL = 'usuario.Usuario'
108 |
109 | # Internationalization
110 | # https://docs.djangoproject.com/en/2.0/topics/i18n/
111 |
112 | LANGUAGE_CODE = 'es-PE'
113 |
114 | TIME_ZONE = 'UTC'
115 |
116 | USE_I18N = True
117 |
118 | USE_L10N = True
119 |
120 | USE_TZ = True
121 |
122 |
123 | # Static files (CSS, JavaScript, Images)
124 | # https://docs.djangoproject.com/en/2.0/howto/static-files/
125 |
126 | STATIC_URL = '/static/'
127 | STATICFILES_DIRS = (BASE_DIR,'static')
128 | LOGIN_REDIRECT_URL = reverse_lazy('index')
129 | LOGOUT_REDIRECT_URL = reverse_lazy('login')
130 | MEDIA_URL = '/media/'
131 | MEDIA_ROOT = os.path.join(BASE_DIR,'media')
--------------------------------------------------------------------------------
/static/js/main.js:
--------------------------------------------------------------------------------
1 | var $ = jQuery.noConflict();
2 |
3 | jQuery(document).ready(function($) {
4 |
5 | "use strict";
6 |
7 | [].slice.call( document.querySelectorAll( 'select.cs-select' ) ).forEach( function(el) {
8 | new SelectFx(el);
9 | });
10 |
11 | jQuery('.selectpicker').selectpicker;
12 |
13 |
14 |
15 |
16 | $('.search-trigger').on('click', function(event) {
17 | event.preventDefault();
18 | event.stopPropagation();
19 | $('.search-trigger').parent('.header-left').addClass('open');
20 | });
21 |
22 | $('.search-close').on('click', function(event) {
23 | event.preventDefault();
24 | event.stopPropagation();
25 | $('.search-trigger').parent('.header-left').removeClass('open');
26 | });
27 |
28 | $('.equal-height').matchHeight({
29 | property: 'max-height'
30 | });
31 |
32 | // var chartsheight = $('.flotRealtime2').height();
33 | // $('.traffic-chart').css('height', chartsheight-122);
34 |
35 |
36 | // Counter Number
37 | $('.count').each(function () {
38 | $(this).prop('Counter',0).animate({
39 | Counter: $(this).text()
40 | }, {
41 | duration: 3000,
42 | easing: 'swing',
43 | step: function (now) {
44 | $(this).text(Math.ceil(now));
45 | }
46 | });
47 | });
48 |
49 |
50 |
51 |
52 | // Menu Trigger
53 | $('#menuToggle').on('click', function(event) {
54 | var windowWidth = $(window).width();
55 | if (windowWidth<1010) {
56 | $('body').removeClass('open');
57 | if (windowWidth<760){
58 | $('#left-panel').slideToggle();
59 | } else {
60 | $('#left-panel').toggleClass('open-menu');
61 | }
62 | } else {
63 | $('body').toggleClass('open');
64 | $('#left-panel').removeClass('open-menu');
65 | }
66 |
67 | });
68 |
69 |
70 | $(".menu-item-has-children.dropdown").each(function() {
71 | $(this).on('click', function() {
72 | var $temp_text = $(this).children('.dropdown-toggle').html();
73 | $(this).children('.sub-menu').prepend('' + $temp_text + '');
74 | });
75 | });
76 |
77 |
78 | // Load Resize
79 | $(window).on("load resize", function(event) {
80 | var windowWidth = $(window).width();
81 | if (windowWidth<1010) {
82 | $('body').addClass('small-device');
83 | } else {
84 | $('body').removeClass('small-device');
85 | }
86 |
87 | });
88 |
89 |
90 | });
91 | function abrir_modal_edicion(url) {
92 | $('#edicion').load(url, function () {
93 | $(this).modal('show');
94 | });
95 | }
96 | function abrir_modal_creacion(url) {
97 | $('#creacion').load(url, function () {
98 | $(this).modal('show');
99 | });
100 | }
101 | function abrir_modal_eliminacion(url) {
102 | $('#eliminacion').load(url, function () {
103 | $(this).modal('show');
104 | });
105 | }
106 | function cerrar_modal_creacion(){
107 | $('#creacion').modal('hide');
108 | }
109 |
110 | function cerrar_modal_edicion() {
111 | $('#edicion').modal('hide');
112 | }
113 | function cerrar_modal_eliminacion() {
114 | $('#eliminacion').modal('hide');
115 | }
116 | function activarBoton(){
117 | if($('#boton_creacion').prop('disabled')){
118 | $('#boton_creacion').prop('disabled',false);
119 | }else{
120 | $('#boton_creacion').prop('disabled', true);
121 | }
122 | }
123 |
124 | function mostrarErroresCreacion(errores){
125 | $('#errores').html("");
126 | let error = "";
127 | for(let item in errores.responseJSON.error){
128 | error += '' + errores.responseJSON.error[item] + '
';
129 | }
130 | $('#errores').append(error);
131 | }
132 | function mostrarErroresEdicion(errores) {
133 | $('#erroresEdicion').html("");
134 | let error = "";
135 | for (let item in errores.responseJSON.error) {
136 | error += '' + errores.responseJSON.error[item] + '
';
137 | }
138 | $('#erroresEdicion').append(error);
139 | }
140 |
141 | function notificacionError(mensaje){
142 | Swal.fire({
143 | title: 'Error!',
144 | text: mensaje,
145 | icon: 'error'
146 | })
147 | }
148 |
149 | function notificacionSuccess(mensaje) {
150 | Swal.fire({
151 | title: 'Buen Trabajo!',
152 | text: mensaje,
153 | icon: 'success'
154 | })
155 | }
--------------------------------------------------------------------------------
/static/js/usuarios/index.js:
--------------------------------------------------------------------------------
1 | function listadoUsuarios(){
2 | $.ajax({
3 | url: "/usuarios/listado_usuarios/",
4 | type:"get",
5 | dataType: "json",
6 | success: function(response){
7 | if($.fn.DataTable.isDataTable('#tabla_usuarios')){
8 | $('#tabla_usuarios').DataTable().destroy();
9 | }
10 | $('#tabla_usuarios tbody').html("");
11 | for(let i = 0;i < response.length;i++){
12 | let fila = '';
13 | fila += '| ' + (i +1 ) + ' | ';
14 | fila += '' + response[i]["fields"]['username'] + ' | ';
15 | fila += '' + response[i]["fields"]['nombres'] + ' | ';
16 | fila += '' + response[i]["fields"]['apellidos'] + ' | ';
17 | fila += '' + response[i]["fields"]['email'] + ' | ';
18 | fila += '';
20 | fila += ' | ';
22 | fila += '
';
23 | $('#tabla_usuarios tbody').append(fila);
24 | }
25 | $('#tabla_usuarios').DataTable({
26 | language: {
27 | "decimal": "",
28 | "emptyTable": "No hay información",
29 | "info": "Mostrando _START_ a _END_ de _TOTAL_ Entradas",
30 | "infoEmpty": "Mostrando 0 to 0 of 0 Entradas",
31 | "infoFiltered": "(Filtrado de _MAX_ total entradas)",
32 | "infoPostFix": "",
33 | "thousands": ",",
34 | "lengthMenu": "Mostrar _MENU_ Entradas",
35 | "loadingRecords": "Cargando...",
36 | "processing": "Procesando...",
37 | "search": "Buscar:",
38 | "zeroRecords": "Sin resultados encontrados",
39 | "paginate": {
40 | "first": "Primero",
41 | "last": "Ultimo",
42 | "next": "Siguiente",
43 | "previous": "Anterior"
44 | },
45 | },
46 | });
47 | },
48 | error: function(error){
49 | console.log(error);
50 | }
51 | });
52 | }
53 | function registrar() {
54 | activarBoton();
55 | $.ajax({
56 | data: $('#form_creacion').serialize(),
57 | url: $('#form_creacion').attr('action'),
58 | type: $('#form_creacion').attr('method'),
59 | success: function (response) {
60 | notificacionSuccess(response.mensaje);
61 | listadoUsuarios();
62 | cerrar_modal_creacion();
63 | },
64 | error: function (error) {
65 | notificacionError(error.responseJSON.mensaje);
66 | mostrarErroresCreacion(error);
67 | activarBoton();
68 | }
69 | });
70 | }
71 | function editar(){
72 | activarBoton();
73 | $.ajax({
74 | data: $('#form_edicion').serialize(),
75 | url: $('#form_edicion').attr('action'),
76 | type: $('#form_edicion').attr('method'),
77 | success: function (response) {
78 | notificacionSuccess(response.mensaje);
79 | listadoUsuarios();
80 | cerrar_modal_edicion();
81 | },
82 | error: function (error) {
83 | notificacionError(error.responseJSON.mensaje);
84 | mostrarErroresEdicion(error);
85 | activarBoton();
86 | }
87 | });
88 | }
89 | function eliminar(pk) {
90 | $.ajax({
91 | data:{
92 | csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
93 | },
94 | url: '/usuarios/eliminar_usuario/'+pk+'/',
95 | type: 'post',
96 | success: function (response) {
97 | notificacionSuccess(response.mensaje);
98 | listadoUsuarios();
99 | cerrar_modal_eliminacion();
100 | },
101 | error: function (error) {
102 | notificacionError(error.responseJSON.mensaje);
103 | }
104 | });
105 | }
106 | $(document).ready(function (){
107 | listadoUsuarios();
108 | });
--------------------------------------------------------------------------------
/static/css/lib/datatable/dataTables.bootstrap.min.css:
--------------------------------------------------------------------------------
1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:0.85em;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap;justify-content:flex-end}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:before,table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:0.9em;display:block;opacity:0.3}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\2191"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{right:0.5em;content:"\2193"}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot>.dataTables_scrollFootInner{box-sizing:content-box}div.dataTables_scrollFoot>.dataTables_scrollFootInner>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-sm>thead>tr>th{padding-right:20px}table.dataTable.table-sm .sorting:before,table.dataTable.table-sm .sorting_asc:before,table.dataTable.table-sm .sorting_desc:before{top:5px;right:0.85em}table.dataTable.table-sm .sorting:after,table.dataTable.table-sm .sorting_asc:after,table.dataTable.table-sm .sorting_desc:after{top:5px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0}
--------------------------------------------------------------------------------
/apps/libro/models.py:
--------------------------------------------------------------------------------
1 | from datetime import timedelta
2 | from django.db import models
3 | from django.core.exceptions import ValidationError
4 | from django.db.models.signals import post_save,pre_save
5 |
6 | from apps.usuario.models import Usuario
7 |
8 | class Autor(models.Model):
9 | id = models.AutoField(primary_key = True)
10 | nombre = models.CharField(max_length = 200, blank = False, null = False)
11 | apellidos = models.CharField(max_length = 220, blank = False, null = False)
12 | nacionalidad = models.CharField(max_length = 100, blank = False, null = False)
13 | descripcion = models.TextField(blank = False,null = False)
14 | estado = models.BooleanField('Estado', default = True)
15 | fecha_creacion = models.DateField('Fecha de creación', auto_now = True, auto_now_add = False)
16 |
17 | all_cruds_types = True
18 |
19 | class Meta:
20 | verbose_name = 'Autor'
21 | verbose_name_plural = 'Autores'
22 | ordering = ['nombre']
23 |
24 | def natural_key(self):
25 | return f'{self.nombre} {self.apellidos}'
26 |
27 | def __str__(self):
28 | return self.nombre
29 |
30 |
31 | class Libro(models.Model):
32 | id = models.AutoField(primary_key = True)
33 | titulo = models.CharField('Título', max_length = 255, blank = False, null = False)
34 | fecha_publicacion = models.DateField('Fecha de publicación', blank = False, null = False)
35 | descripcion = models.TextField('Descripción',null = True,blank = True)
36 | cantidad = models.PositiveIntegerField('Cantidad o Stock',default = 1)
37 | imagen = models.ImageField('Imagen', upload_to='libros/',max_length=255,null = True,blank = True)
38 | autor = models.ManyToManyField(Autor)
39 | fecha_creacion = models.DateField('Fecha de creación', auto_now = True, auto_now_add = False)
40 | estado = models.BooleanField(default = True, verbose_name = 'Estado')
41 |
42 | def natural_key(self):
43 | return self.titulo
44 |
45 | class Meta:
46 | verbose_name = 'Libro'
47 | verbose_name_plural = 'Libros'
48 | ordering = ['titulo']
49 |
50 | def __str__(self):
51 | return self.titulo
52 |
53 |
54 | def obtener_autores(self):
55 | autores = str([autor for autor in self.autor_id.all().values_list('nombre',flat = True)]).replace("[","").replace("]","").replace("'","")
56 | return autores
57 |
58 | class Reserva(models.Model):
59 | """Model definition for Reserva."""
60 |
61 | # TODO: Define fields here
62 | id = models.AutoField(primary_key = True)
63 | libro = models.ForeignKey(Libro, on_delete=models.CASCADE)
64 | usuario = models.ForeignKey(Usuario, on_delete=models.CASCADE)
65 | cantidad_dias = models.SmallIntegerField('Cantidad de Dias a Reservar',default = 7)
66 | fecha_creacion = models.DateField('Fecha de creación', auto_now = False, auto_now_add = True)
67 | fecha_vencimiento = models.DateField('Fecha de vencimiento de la reserva', auto_now=False, auto_now_add=False, null = True, blank = True)
68 | estado = models.BooleanField(default = True, verbose_name = 'Estado')
69 |
70 | class Meta:
71 | """Meta definition for Reserva."""
72 |
73 | verbose_name = 'Reserva'
74 | verbose_name_plural = 'Reservas'
75 |
76 | def __str__(self):
77 | """Unicode representation of Reserva."""
78 | return f'Reserva de Libro {self.libro} por {self.usuario}'
79 |
80 | def quitar_relacion_autor_libro(sender,instance,**kwargs):
81 | if instance.estado == False:
82 | autor = instance.id
83 | libros = Libro.objects.filter(autor_id=autor)
84 | for libro in libros:
85 | libro.autor_id.remove(autor)
86 |
87 | def reducir_cantidad_libro(sender,instance,**kwargs):
88 | libro = instance.libro
89 | if libro.cantidad > 0:
90 | libro.cantidad = libro.cantidad - 1
91 | libro.save()
92 |
93 | def validar_creacion_reserva(sender,instance,**kwargs):
94 | libro = instance.libro
95 | if libro.cantidad < 1:
96 | raise Exception("No puede realizar esta reserva")
97 |
98 | def agregar_fecha_vencimiento_reserva(sender,instance,**kwargs):
99 | if instance.fecha_vencimiento is None or instance.fecha_vencimiento == '':
100 | instance.fecha_vencimiento = instance.fecha_creacion + timedelta(days = instance.cantidad_dias)
101 | instance.save()
102 |
103 | def saludar(sender,instance,**kwargs):
104 | print("Hola desde signal de autor")
105 |
106 | post_save.connect(quitar_relacion_autor_libro,sender = Autor)
107 | #post_save.connect(saludar,sender = Autor)
108 | post_save.connect(reducir_cantidad_libro,sender = Reserva)
109 | post_save.connect(agregar_fecha_vencimiento_reserva,sender = Reserva)
110 | #pre_save.connect(validar_creacion_reserva,sender = Reserva)
--------------------------------------------------------------------------------
/static/js/libro/libro.js:
--------------------------------------------------------------------------------
1 | function listadoLibros() {
2 | $.ajax({
3 | url: "/libro/listado_libros/",
4 | type: "get",
5 | dataType: "json",
6 | success: function (response) {
7 | if ($.fn.DataTable.isDataTable('#tabla_libros')) {
8 | $('#tabla_libros').DataTable().destroy();
9 | }
10 | $('#tabla_libros tbody').html("");
11 | for (let i = 0; i < response.length; i++) {
12 | let fila = '';
13 | fila += '| ' + (i + 1) + ' | ';
14 | fila += '' + response[i]["fields"]['titulo'] + ' | ';
15 | fila += '' + response[i]["fields"]['fecha_publicacion'] + ' | ';
16 | if (response[i]["fields"]['autor_id'] == ''){
17 | fila += 'Desconocido | ';
18 | }else{
19 | fila += '' + response[i]["fields"]['autor_id'] + ' | ';
20 | }
21 | fila += '';
23 | fila += ' | ';
25 | fila += '
';
26 | $('#tabla_libros tbody').append(fila);
27 | }
28 | $('#tabla_libros').DataTable({
29 | language: {
30 | "decimal": "",
31 | "emptyTable": "No hay información",
32 | "info": "Mostrando _START_ a _END_ de _TOTAL_ Entradas",
33 | "infoEmpty": "Mostrando 0 to 0 of 0 Entradas",
34 | "infoFiltered": "(Filtrado de _MAX_ total entradas)",
35 | "infoPostFix": "",
36 | "thousands": ",",
37 | "lengthMenu": "Mostrar _MENU_ Entradas",
38 | "loadingRecords": "Cargando...",
39 | "processing": "Procesando...",
40 | "search": "Buscar:",
41 | "zeroRecords": "Sin resultados encontrados",
42 | "paginate": {
43 | "first": "Primero",
44 | "last": "Ultimo",
45 | "next": "Siguiente",
46 | "previous": "Anterior"
47 | },
48 | },
49 | });
50 | },
51 | error: function (error) {
52 | console.log(error);
53 | }
54 | });
55 | }
56 | function registrar() {
57 | activarBoton();
58 | var data = new FormData($('#form_creacion').get(0));
59 | $.ajax({
60 | url: $('#form_creacion').attr('action'),
61 | type: $('#form_creacion').attr('method'),
62 | data: data,
63 | cache: false,
64 | processData: false,
65 | contentType: false,
66 | success: function (response) {
67 | notificacionSuccess(response.mensaje);
68 | listadoLibros();
69 | cerrar_modal_creacion();
70 | },
71 | error: function (error) {
72 | notificacionError(error.responseJSON.mensaje);
73 | mostrarErroresCreacion(error);
74 | activarBoton();
75 | }
76 | });
77 | }
78 | function editar() {
79 | activarBoton();
80 | var data = new FormData($('#form_edicion').get(0));
81 | $.ajax({
82 | url: $('#form_edicion').attr('action'),
83 | type: $('#form_edicion').attr('method'),
84 | data: data,
85 | cache: false,
86 | processData: false,
87 | contentType: false,
88 | success: function (response) {
89 | notificacionSuccess(response.mensaje);
90 | listadoLibros();
91 | cerrar_modal_edicion();
92 | },
93 | error: function (error) {
94 | notificacionError(error.responseJSON.mensaje);
95 | mostrarErroresEdicion(error);
96 | activarBoton();
97 | },
98 | });
99 | }
100 | function eliminar(pk) {
101 | $.ajax({
102 | data: {
103 | csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
104 | },
105 | url: '/libro/eliminar_libro/' + pk + '/',
106 | type: 'post',
107 | success: function (response) {
108 | notificacionSuccess(response.mensaje);
109 | listadoLibros();
110 | cerrar_modal_eliminacion();
111 | },
112 | error: function (error) {
113 | notificacionError(error.responseJSON.mensaje);
114 | }
115 | });
116 | }
117 | $(document).ready(function () {
118 | listadoLibros();
119 | });
--------------------------------------------------------------------------------
/apps/usuario/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from django.contrib.auth.forms import AuthenticationForm
3 | from apps.usuario.models import Usuario
4 |
5 | class FormularioLogin(AuthenticationForm):
6 | def __init__(self, *args, **kwargs):
7 | super(FormularioLogin, self).__init__(*args,**kwargs)
8 | self.fields['username'].widget.attrs['class'] = 'form-control'
9 | self.fields['username'].widget.attrs['placeholder'] = 'Nombre de Usuario'
10 | self.fields['password'].widget.attrs['class'] = 'form-control'
11 | self.fields['password'].widget.attrs['placeholder'] = 'Contraseña'
12 |
13 | class FormularioUsuario(forms.ModelForm):
14 | """ Formulario de Registro de un Usuario en la base de datos
15 |
16 | Variables:
17 |
18 | - password1: Contraseña
19 | - password2: Verificación de la contraseña
20 |
21 | """
22 | password1 = forms.CharField(label = 'Contraseña',widget = forms.PasswordInput(
23 | attrs = {
24 | 'class': 'form-control',
25 | 'placeholder': 'Ingrese su contraseña...',
26 | 'id': 'password1',
27 | 'required':'required',
28 | }
29 | ))
30 |
31 | password2 = forms.CharField(label = 'Contraseña de Confirmación', widget = forms.PasswordInput(
32 | attrs={
33 | 'class': 'form-control',
34 | 'placeholder': 'Ingrese nuevamente su contraseña...',
35 | 'id': 'password2',
36 | 'required': 'required',
37 | }
38 | ))
39 |
40 | class Meta:
41 | model = Usuario
42 | fields = ('email','username','nombres','apellidos','rol')
43 | widgets = {
44 | 'email': forms.EmailInput(
45 | attrs = {
46 | 'class': 'form-control',
47 | 'placeholder': 'Correo Electrónico',
48 | }
49 | ),
50 | 'nombres': forms.TextInput(
51 | attrs={
52 | 'class': 'form-control',
53 | 'placeholder': 'Ingrese su nombre',
54 | }
55 | ),
56 | 'apellidos': forms.TextInput(
57 | attrs = {
58 | 'class': 'form-control',
59 | 'placeholder': 'Ingrese sus apellidos',
60 | }
61 | ),
62 | 'username': forms.TextInput(
63 | attrs = {
64 | 'class': 'form-control',
65 | 'placeholder': 'Ingrese su nombre de usuario',
66 | }
67 | ),
68 | 'rol': forms.Select(
69 | attrs = {
70 | 'class': 'form-control'
71 | }
72 | )
73 | }
74 |
75 | def clean_password2(self):
76 | """ Validación de Contraseña
77 |
78 | Metodo que valida que ambas contraseñas ingresadas sean igual, esto antes de ser encriptadas
79 | y guardadas en la base dedatos, Retornar la contraseña Válida.
80 |
81 | Excepciones:
82 | - ValidationError -- cuando las contraseñas no son iguales muestra un mensaje de error
83 | """
84 | password1 = self.cleaned_data.get('password1')
85 | password2 = self.cleaned_data.get('password2')
86 | if password1 != password2:
87 | raise forms.ValidationError('Contraseñas no coinciden!')
88 | return password2
89 |
90 | def save(self,commit = True):
91 | user = super().save(commit=False)
92 | user.set_password(self.cleaned_data['password1'])
93 | if commit:
94 | user.save()
95 | return user
96 |
97 |
98 | class CambiarPasswordForm(forms.Form):
99 | password1 = forms.CharField(label = 'Contraseña',widget = forms.PasswordInput(
100 | attrs = {
101 | 'class': 'form-control',
102 | 'placeholder': 'Ingrese su nueva contraseña...',
103 | 'id': 'password1',
104 | 'required':'required',
105 | }
106 | ))
107 |
108 | password2 = forms.CharField(label = 'Contraseña de Confirmación', widget = forms.PasswordInput(
109 | attrs={
110 | 'class': 'form-control',
111 | 'placeholder': 'Ingrese nuevamente la nueva contraseña...',
112 | 'id': 'password2',
113 | 'required': 'required',
114 | }
115 | ))
116 |
117 | def clean_password2(self):
118 | """ Validación de Contraseña
119 |
120 | Metodo que valida que ambas contraseñas ingresadas sean igual, esto antes de ser encriptadas
121 | y guardadas en la base dedatos, Retornar la contraseña Válida.
122 |
123 | Excepciones:
124 | - ValidationError -- cuando las contraseñas no son iguales muestra un mensaje de error
125 | """
126 | password1 = self.cleaned_data.get('password1')
127 | password2 = self.cleaned_data.get('password2')
128 | if password1 != password2:
129 | raise forms.ValidationError('Contraseñas no coinciden!')
130 | return password2
--------------------------------------------------------------------------------
/apps/usuario/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import AbstractBaseUser,BaseUserManager,PermissionsMixin
3 | from django.contrib.auth.models import Permission,Group
4 | from django.contrib.contenttypes.models import ContentType
5 |
6 | class Rol(models.Model):
7 | """Model definition for Rol."""
8 |
9 | # TODO: Define fields here
10 | id = models.AutoField(primary_key = True)
11 | rol = models.CharField('Rol', max_length=50,unique = True)
12 |
13 | class Meta:
14 | """Meta definition for Rol."""
15 |
16 | verbose_name = 'Rol'
17 | verbose_name_plural = 'Rols'
18 |
19 | def __str__(self):
20 | """Unicode representation of Rol."""
21 | return self.rol
22 |
23 | def save(self,*args,**kwargs):
24 | permisos_defecto = ['add','change','delete','view']
25 | if not self.id:
26 | nuevo_grupo,creado = Group.objects.get_or_create(name = f'{self.rol}')
27 | for permiso_temp in permisos_defecto:
28 | permiso,created = Permission.objects.update_or_create(
29 | name = f'Can {permiso_temp} {self.rol}',
30 | content_type = ContentType.objects.get_for_model(Rol),
31 | codename = f'{permiso_temp}_{self.rol}'
32 | )
33 | if creado:
34 | nuevo_grupo.permissions.add(permiso.id)
35 | super().save(*args,**kwargs)
36 | else:
37 | rol_antiguo = Rol.objects.filter(id = self.id).values('rol').first()
38 | if rol_antiguo['rol'] == self.rol:
39 | super().save(*args,**kwargs)
40 | else:
41 | Group.objects.filter(name = rol_antiguo['rol']).update(name = f'{self.rol}')
42 | for permiso_temp in permisos_defecto:
43 | Permission.objects.filter(codename = f"{permiso_temp}_{rol_antiguo['rol']}").update(
44 | codename = f'{permiso_temp}_{self.rol}',
45 | name = f'Can {permiso_temp} {self.rol}'
46 | )
47 | super().save(*args,**kwargs)
48 |
49 |
50 |
51 | class UsuarioManager(BaseUserManager):
52 | def _create_user(self, username, email, nombres, password, is_staff, is_superuser, **extra_fields):
53 | user = self.model(
54 | username=username,
55 | email=email,
56 | nombres=nombres,
57 | is_staff=is_staff,
58 | is_superuser=is_superuser,
59 | **extra_fields
60 | )
61 | user.set_password(password)
62 | user.save(using=self.db)
63 | return user
64 |
65 | def create_user(self, username, email, nombres, is_staff, password=None, **extra_fields):
66 | return self._create_user(username, email, nombres, password, is_staff, False, **extra_fields)
67 |
68 | def create_superuser(self,username,email,nombres,password = None,**extra_fields):
69 | return self._create_user(username, email, nombres, password, True, True, **extra_fields)
70 |
71 | class Usuario(AbstractBaseUser, PermissionsMixin):
72 | username = models.CharField('Nombre de usuario',unique = True, max_length=100)
73 | email = models.EmailField('Correo Electrónico', max_length=254,unique = True)
74 | nombres = models.CharField('Nombres', max_length=200, blank = True, null = True)
75 | apellidos = models.CharField('Apellidos', max_length=200,blank = True, null = True)
76 | rol = models.ForeignKey(Rol, on_delete=models.CASCADE,blank = True,null = True)
77 | imagen = models.ImageField('Imagen de Perfil', upload_to='perfil/', max_length=200,blank = True,null = True)
78 | is_active = models.BooleanField(default = True)
79 | is_staff = models.BooleanField(default = False)
80 | objects = UsuarioManager()
81 |
82 | USERNAME_FIELD = 'username'
83 | REQUIRED_FIELDS = ['email','nombres']
84 |
85 | class Meta:
86 | permissions = [('permiso_desde_codigo','Este es un permiso creado desde código'),
87 | ('segundo_permiso_codigo','Segundo permiso creado desde codigo')]
88 |
89 | def __str__(self):
90 | return f'{self.nombres},{self.apellidos}'
91 |
92 |
93 | def save(self,*args,**kwargs):
94 | if not self.id:
95 | super().save(*args,**kwargs)
96 | if self.rol is not None:
97 | grupo = Group.objects.filter(name = self.rol.rol).first()
98 | if grupo:
99 | self.groups.add(grupo)
100 | super().save(*args,**kwargs)
101 | else:
102 | if self.rol is not None:
103 | grupo_antiguo = Usuario.objects.filter(id = self.id).values('rol__rol').first()
104 | #print(grupo_antiguo['rol__rol'])
105 | #print(self.rol.rol)
106 | if grupo_antiguo['rol__rol'] == self.rol.rol:
107 | print("Entro en igualdad de roles")
108 | super().save(*args,**kwargs)
109 | else:
110 | grupo_anterior = Group.objects.filter(name = grupo_antiguo['rol__rol']).first()
111 | if grupo_anterior:
112 | print(grupo_anterior)
113 | self.groups.remove(grupo_anterior)
114 | nuevo_grupo = Group.objects.filter(name = self.rol.rol).first()
115 | if nuevo_grupo:
116 | self.groups.add(nuevo_grupo)
117 | super().save(*args,**kwargs)
--------------------------------------------------------------------------------
/static/js/libro/autor.js:
--------------------------------------------------------------------------------
1 | function listadoAutores() {
2 | $.ajax({
3 | url: "/libro/listado_autor/",
4 | type: "get",
5 | dataType: "json",
6 | success: function (response) {
7 | if ($.fn.DataTable.isDataTable('#tabla_autores')) {
8 | $('#tabla_autores').DataTable().destroy();
9 | }
10 | $('#tabla_autores tbody').html("");
11 | for (let i = 0; i < response.length; i++) {
12 | let fila = '';
13 | fila += '| ' + (i + 1) + ' | ';
14 | fila += '' + response[i]["fields"]['nombre'] + ' | ';
15 | fila += '' + response[i]["fields"]['apellidos'] + ' | ';
16 | fila += '' + response[i]["fields"]['nacionalidad'] + ' | ';
17 | fila += '' + response[i]["fields"]['descripcion'] + ' | ';
18 | fila += '';
20 | fila += ' | ';
22 | fila += '
';
23 | $('#tabla_autores tbody').append(fila);
24 | }
25 | $('#tabla_autores').DataTable({
26 | "language": {
27 | "decimal": "",
28 | "emptyTable": "No hay información",
29 | "info": "Mostrando _START_ a _END_ de _TOTAL_ Entradas",
30 | "infoEmpty": "Mostrando 0 to 0 of 0 Entradas",
31 | "infoFiltered": "(Filtrado de _MAX_ total entradas)",
32 | "infoPostFix": "",
33 | "thousands": ",",
34 | "lengthMenu": "Mostrar _MENU_ Entradas",
35 | "loadingRecords": "Cargando...",
36 | "processing": "Procesando...",
37 | "search": "Buscar:",
38 | "zeroRecords": "Sin resultados encontrados",
39 | "paginate": {
40 | "first": "Primero",
41 | "last": "Ultimo",
42 | "next": "Siguiente",
43 | "previous": "Anterior"
44 | },
45 | },
46 | });
47 | },
48 | error: function (error) {
49 | console.log(error);
50 | }
51 | });
52 | }
53 | function registrar() {
54 | activarBoton();
55 | $.ajax({
56 | data: $('#form_creacion').serialize(),
57 | url: $('#form_creacion').attr('action'),
58 | type: $('#form_creacion').attr('method'),
59 | success: function (response) {
60 | notificacionSuccess(response.mensaje);
61 | listadoAutores();
62 | cerrar_modal_creacion();
63 | },
64 | error: function (error) {
65 | notificacionError(error.responseJSON.mensaje);
66 | mostrarErroresCreacion(error);
67 | activarBoton();
68 | }
69 | });
70 | }
71 | function editar() {
72 | activarBoton();
73 | $.ajax({
74 | data: $('#form_edicion').serialize(),
75 | url: $('#form_edicion').attr('action'),
76 | type: $('#form_edicion').attr('method'),
77 | success: function (response) {
78 | notificacionSuccess(response.mensaje);
79 | listadoAutores();
80 | cerrar_modal_edicion();
81 | },
82 | error: function (error) {
83 | notificacionError(error.responseJSON.mensaje);
84 | mostrarErroresEdicion(error);
85 | activarBoton();
86 | }
87 | });
88 | }
89 | function eliminar(pk) {
90 | $.ajax({
91 | data: {
92 | csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
93 | },
94 | url: '/libro/eliminar_autor/' + pk + '/',
95 | type: 'post',
96 | success: function (response) {
97 | notificacionSuccess(response.mensaje);
98 | listadoAutores();
99 | cerrar_modal_eliminacion();
100 | },
101 | error: function (error) {
102 | notificacionError(error.responseJSON.mensaje);
103 | }
104 | });
105 | }
106 | $(document).ready(function () {
107 | //listadoAutores();
108 | $('#tabla_autores').DataTable({
109 | "serverSide": true,
110 | "processing": true,
111 | "ajax": function(data,callback,settings){
112 | var columna_filtro = data.columns[data.order[0].column].data.replace(/\./g,"__");
113 |
114 | $.get('/libro/listado_autor/',{
115 | limite: data.length,
116 | inicio: data.start,
117 | filtro: data.search.value,
118 | order_by: columna_filtro
119 | }, function(res){
120 | callback({
121 | recordsTotal:res.length,
122 | recordsFiltered:res.length,
123 | data:res.objects
124 | });
125 | },
126 | );
127 | },
128 | "columns":[
129 | { "data": "id" },
130 | { "data": "nombre" },
131 | { "data": "apellidos" },
132 | { "data": "nacionalidad" },
133 | { "data": "descripcion" },
134 | ]
135 | });
136 | });
--------------------------------------------------------------------------------
/static/js/init/weather-init.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | //"use strict";
3 |
4 | function loadWeather(location, woeid) {
5 | $.simpleWeather({
6 | location: location,
7 | woeid: woeid,
8 | unit: 'f',
9 | success: function (weather) {
10 | html = '';
11 | html += '
';
12 | html += '
' + weather.currently + '
';
13 | html += '
' + weather.forecast[0].day + ', ' + weather.forecast[0].date+ '
';
14 | html += '
';
15 |
16 |
17 | html += '';
18 | html += '
' + weather.city + ' '+ weather.region + '
';
19 | html += '
' + weather.alt.temp + '°C
';
20 | html += '
';
21 |
22 | html += '';
23 |
24 | html += '
' + weather.forecast[1].day + ' ' + weather.forecast[1].alt.high + '° ' + weather.forecast[1].alt.low + '°
';
25 | html += '
' + weather.forecast[2].day + ' ' + weather.forecast[2].alt.high + '° ' + weather.forecast[2].alt.low + '°
';
26 | html += '
' + weather.forecast[3].day + ' ' + weather.forecast[3].alt.high + '° ' + weather.forecast[3].alt.low + '°
';
27 | html += '
' + weather.forecast[4].day + ' ' + weather.forecast[4].alt.high + '° ' + weather.forecast[4].alt.low + '°
';
28 | html += '
' + weather.forecast[5].day + ' ' + weather.forecast[5].alt.high + '° ' + weather.forecast[5].alt.low + '°
';
29 | html += '
';
30 |
31 | $("#weather-one").html(html);
32 | },
33 | error: function (error) {
34 | $("#weather-one").html('' + error + '
');
35 | }
36 | });
37 | }
38 |
39 |
40 | // init
41 | loadWeather('New York City', '');
42 |
43 | })(jQuery);
44 |
45 |
46 | (function ($) {
47 | //"use strict";
48 |
49 | function loadWeather(location, woeid) {
50 | $.simpleWeather({
51 | location: location,
52 | woeid: woeid,
53 | unit: 'f',
54 | success: function (weather) {
55 |
56 | html = ' ' + weather.temp + '°' + weather.units.temp + '
';
57 | html += '' + weather.city + ', ' + weather.region + '
';
58 | html += '' + weather.currently + '
';
59 | html += '' + weather.alt.temp + '°C
';
60 |
61 | $("#weather-two").html(html);
62 | },
63 | error: function (error) {
64 | $("#weather-two").html('' + error + '
');
65 | }
66 | });
67 | }
68 |
69 |
70 | // init
71 | loadWeather('New York City', '');
72 |
73 | })(jQuery);
74 |
75 |
76 |
77 | (function ($) {
78 | //"use strict";
79 |
80 | function loadWeather(location, woeid) {
81 | $.simpleWeather({
82 | location: location,
83 | woeid: woeid,
84 | unit: 'f',
85 | success: function (weather) {
86 |
87 | html = ' ' + weather.temp + '°' + weather.units.temp + '
';
88 | html += '' + weather.city + ', ' + weather.region + '
';
89 | html += '' + weather.currently + '
';
90 | html += '' + weather.alt.temp + '°C
';
91 |
92 | $("#weather-three").html(html);
93 | },
94 | error: function (error) {
95 | $("#weather-three").html('' + error + '
');
96 | }
97 | });
98 | }
99 |
100 |
101 | // init
102 | loadWeather('Sydney', '');
103 |
104 | })(jQuery);
105 |
106 |
107 | (function ($) {
108 | //"use strict";
109 |
110 | function loadWeather(location, woeid) {
111 | $.simpleWeather({
112 | location: location,
113 | woeid: woeid,
114 | unit: 'f',
115 | success: function (weather) {
116 |
117 | html = ' ' + weather.temp + '°' + weather.units.temp + '
';
118 | html += '' + weather.city + ', ' + weather.region + '
';
119 | html += '' + weather.currently + '
';
120 | html += '' + weather.alt.temp + '°C
';
121 |
122 | $("#weather-four").html(html);
123 | },
124 | error: function (error) {
125 | $("#weather-four").html('' + error + '
');
126 | }
127 | });
128 | }
129 |
130 |
131 | // init
132 | loadWeather('New York', '');
133 |
134 | })(jQuery);
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/static/js/init/gmap-init.js:
--------------------------------------------------------------------------------
1 | (function($){
2 |
3 | var map;
4 | $(document).ready(function(){
5 | map = new GMaps({
6 | el: '#basic-map',
7 | lat: -12.043333,
8 | lng: -77.028333,
9 | zoomControl : true,
10 | zoomControlOpt: {
11 | style : 'SMALL',
12 | position: 'TOP_LEFT'
13 | },
14 | panControl : false,
15 | streetViewControl : false,
16 | mapTypeControl: false,
17 | overviewMapControl: false
18 | });
19 | });
20 |
21 |
22 |
23 |
24 | var map, infoWindow;
25 | $(document).ready(function(){
26 | infoWindow = new google.maps.InfoWindow({});
27 | map = new GMaps({
28 | el: '#map-2',
29 | zoom: 11,
30 | lat: 41.850033,
31 | lng: -87.6500523
32 | });
33 | map.loadFromFusionTables({
34 | query: {
35 | select: '\'Geocodable address\'',
36 | from: '1mZ53Z70NsChnBMm-qEYmSDOvLXgrreLTkQUvvg'
37 | },
38 | suppressInfoWindows: true,
39 | events: {
40 | click: function(point){
41 | infoWindow.setContent('You clicked here!');
42 | infoWindow.setPosition(point.latLng);
43 | infoWindow.open(map.map);
44 | }
45 | }
46 | });
47 | });
48 |
49 |
50 |
51 |
52 | var map, rectangle, polygon, circle;
53 | $(document).ready(function(){
54 | map = new GMaps({
55 | el: '#map-3',
56 | lat: -12.043333,
57 | lng: -77.028333
58 | });
59 | var bounds = [[-12.030397656836609,-77.02373871559225],[-12.034804866577001,-77.01154422636042]];
60 | rectangle = map.drawRectangle({
61 | bounds: bounds,
62 | strokeColor: '#BBD8E9',
63 | strokeOpacity: 1,
64 | strokeWeight: 3,
65 | fillColor: '#BBD8E9',
66 | fillOpacity: 0.6
67 | });
68 |
69 | var paths = [[-12.040397656836609,-77.03373871559225],[-12.040248585302038,-77.03993927003302],[-12.050047116528843,-77.02448169303511],[-12.044804866577001,-77.02154422636042]];
70 | polygon = map.drawPolygon({
71 | paths: paths,
72 | strokeColor: '#25D359',
73 | strokeOpacity: 1,
74 | strokeWeight: 3,
75 | fillColor: '#25D359',
76 | fillOpacity: 0.6
77 | });
78 | var lat = -12.040504866577001;
79 | var lng = -77.02024422636042;
80 | circle = map.drawCircle({
81 | lat: lat,
82 | lng: lng,
83 | radius: 350,
84 | strokeColor: '#432070',
85 | strokeOpacity: 1,
86 | strokeWeight: 3,
87 | fillColor: '#432070',
88 | fillOpacity: 0.6
89 | });
90 | for(var i in paths){
91 | bounds.push(paths[i]);
92 | }
93 | var b = [];
94 | for(var i in bounds){
95 | latlng = new google.maps.LatLng(bounds[i][0], bounds[i][1]);
96 | b.push(latlng);
97 | }
98 | for(var i in paths){
99 | latlng = new google.maps.LatLng(paths[i][0], paths[i][1]);
100 | b.push(latlng);
101 | }
102 | map.fitLatLngBounds(b);
103 | });
104 |
105 |
106 |
107 |
108 |
109 |
110 | var map;
111 | $(document).ready(function(){
112 | map = new GMaps({
113 | el: '#map-4',
114 | lat: -12.043333,
115 | lng: -77.028333
116 | });
117 | //locations request
118 | map.getElevations({
119 | locations : [[-12.040397656836609,-77.03373871559225], [-12.050047116528843,-77.02448169303511], [-12.044804866577001,-77.02154422636042]],
120 | callback : function (result, status){
121 | if (status == google.maps.ElevationStatus.OK) {
122 | for (var i in result){
123 | map.addMarker({
124 | lat: result[i].location.lat(),
125 | lng: result[i].location.lng(),
126 | title: 'Marker with InfoWindow',
127 | infoWindow: {
128 | content: 'The elevation is '+result[i].elevation+' in meters
'
129 | }
130 | });
131 | }
132 | }
133 | }
134 | });
135 | });
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 | var map;
153 | $(document).ready(function(){
154 | var map = new GMaps({
155 | el: '#map-5',
156 | lat: -12.043333,
157 | lng: -77.028333
158 | });
159 |
160 | GMaps.geolocate({
161 | success: function(position){
162 | map.setCenter(position.coords.latitude, position.coords.longitude);
163 | },
164 | error: function(error){
165 | alert('Geolocation failed: '+error.message);
166 | },
167 | not_supported: function(){
168 | alert("Your browser does not support geolocation");
169 | },
170 | always: function(){
171 | alert("Done!");
172 | }
173 | });
174 | });
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | var map, infoWindow;
187 | $(document).ready(function(){
188 | infoWindow = new google.maps.InfoWindow({});
189 | map = new GMaps({
190 | el: '#map-6',
191 | zoom: 12,
192 | lat: 40.65,
193 | lng: -73.95
194 | });
195 | map.loadFromKML({
196 | url: 'https://api.flickr.com/services/feeds/geo/?g=322338@N20&lang=en-us&format=feed-georss',
197 | suppressInfoWindows: true,
198 | events: {
199 | click: function(point){
200 | infoWindow.setContent(point.featureData.infoWindowHtml);
201 | infoWindow.setPosition(point.latLng);
202 | infoWindow.open(map.map);
203 | }
204 | }
205 | });
206 | });
207 |
208 |
209 |
210 |
211 |
212 | var map;
213 | $(function () {
214 | map = new GMaps({
215 | el: "#map-7",
216 | lat: -12.043333,
217 | lng: -77.028333,
218 | zoom: 3
219 | });
220 |
221 | map.addLayer('weather', {
222 | clickable: false
223 | });
224 | map.addLayer('clouds');
225 | });
226 |
227 |
228 |
229 |
230 |
231 |
232 | map = new GMaps({
233 | el: '#map-8',
234 | zoom: 16,
235 | lat: -12.043333,
236 | lng: -77.028333,
237 | click: function(e){
238 | alert('click');
239 | },
240 | dragend: function(e){
241 | alert('dragend');
242 | }
243 | });
244 |
245 |
246 | })(jQuery);
247 |
--------------------------------------------------------------------------------
/static/js/init/vector-init.js:
--------------------------------------------------------------------------------
1 | ( function ( $ ) {
2 | "use strict";
3 |
4 |
5 |
6 |
7 |
8 | jQuery( '#vmap' ).vectorMap( {
9 | map: 'world_en',
10 | backgroundColor: null,
11 | color: '#ffffff',
12 | hoverOpacity: 0.7,
13 | selectedColor: '#1de9b6',
14 | enableZoom: true,
15 | showTooltip: true,
16 | values: sample_data,
17 | scaleColors: [ '#1de9b6', '#03a9f5' ],
18 | normalizeFunction: 'polynomial'
19 | } );
20 |
21 | jQuery( '#vmap2' ).vectorMap( {
22 | map: 'dz_fr',
23 | color: '#007BFF',
24 | borderColor: '#fff',
25 | backgroundColor: '#fff',
26 | borderOpacity: 1,
27 | enableZoom: true,
28 | showTooltip: true
29 | } );
30 |
31 | jQuery( '#vmap3' ).vectorMap( {
32 | map: 'argentina_en',
33 | color: '#007BFF',
34 | borderColor: '#fff',
35 | backgroundColor: '#fff',
36 | onRegionClick: function ( element, code, region ) {
37 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
38 |
39 | alert( message );
40 | }
41 | } );
42 |
43 | jQuery( '#vmap4' ).vectorMap( {
44 | map: 'brazil_br',
45 | color: '#007BFF',
46 | borderColor: '#fff',
47 | backgroundColor: '#fff',
48 | onRegionClick: function ( element, code, region ) {
49 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
50 |
51 | alert( message );
52 | }
53 | } );
54 |
55 | jQuery( '#vmap5' ).vectorMap( {
56 | map: 'france_fr',
57 | color: '#007BFF',
58 | borderColor: '#fff',
59 | backgroundColor: '#fff',
60 | enableZoom: true,
61 | showTooltip: true
62 | } );
63 |
64 | jQuery( '#vmap6' ).vectorMap( {
65 | map: 'germany_en',
66 | color: '#007BFF',
67 | borderColor: '#fff',
68 | backgroundColor: '#fff',
69 | onRegionClick: function ( element, code, region ) {
70 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
71 |
72 | alert( message );
73 | }
74 | } );
75 |
76 | jQuery( '#vmap7' ).vectorMap( {
77 | map: 'greece',
78 | color: '#007BFF',
79 | borderColor: '#fff',
80 | backgroundColor: '#fff',
81 | onRegionClick: function ( element, code, region ) {
82 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
83 |
84 | alert( message );
85 | }
86 | } );
87 |
88 | jQuery( '#vmap8' ).vectorMap( {
89 | map: 'iran_ir',
90 | onRegionClick: function ( element, code, region ) {
91 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
92 |
93 | alert( message );
94 | }
95 | } );
96 |
97 | jQuery( '#vmap9' ).vectorMap( {
98 | map: 'iraq',
99 | color: '#007BFF',
100 | borderColor: '#fff',
101 | backgroundColor: '#fff',
102 | onRegionClick: function ( element, code, region ) {
103 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
104 |
105 | alert( message );
106 | }
107 | } );
108 |
109 | jQuery( '#vmap10' ).vectorMap( {
110 | map: 'russia_en',
111 | color: '#007BFF',
112 | borderColor: '#fff',
113 | backgroundColor: '#fff',
114 | hoverOpacity: 0.7,
115 | selectedColor: '#999999',
116 | enableZoom: true,
117 | showTooltip: true,
118 | scaleColors: [ '#C8EEFF', '#006491' ],
119 | normalizeFunction: 'polynomial'
120 | } );
121 |
122 | jQuery( '#vmap11' ).vectorMap( {
123 | map: 'tunisia',
124 | color: '#007BFF',
125 | borderColor: '#fff',
126 | backgroundColor: '#fff',
127 | onRegionClick: function ( element, code, region ) {
128 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
129 |
130 | alert( message );
131 | }
132 | } );
133 |
134 | jQuery( '#vmap12' ).vectorMap( {
135 | map: 'europe_en',
136 | color: '#007BFF',
137 | borderColor: '#fff',
138 | backgroundColor: '#fff',
139 | enableZoom: true,
140 | showTooltip: true
141 | } );
142 |
143 | jQuery( '#vmap13' ).vectorMap( {
144 | map: 'usa_en',
145 | color: '#007BFF',
146 | borderColor: '#fff',
147 | backgroundColor: '#fff',
148 | enableZoom: true,
149 | showTooltip: true,
150 | selectedColor: null,
151 | hoverColor: null,
152 | colors: {
153 | mo: '#001BFF',
154 | fl: '#001BFF',
155 | or: '#001BFF'
156 | },
157 | onRegionClick: function ( event, code, region ) {
158 | event.preventDefault();
159 | }
160 | } );
161 |
162 | jQuery( '#vmap14' ).vectorMap( {
163 | map: 'turkey',
164 | color: '#007BFF',
165 | borderColor: '#fff',
166 | backgroundColor: '#fff',
167 | onRegionClick: function ( element, code, region ) {
168 | var message = 'You clicked "' + region + '" which has the code: ' + code.toUpperCase();
169 | alert( message );
170 | }
171 | } );
172 |
173 |
174 |
175 | } )( jQuery );
176 |
177 |
178 |
179 | var map;
180 |
181 | jQuery( document ).ready( function () {
182 |
183 | // Store currentRegion
184 | var currentRegion = 'fl';
185 |
186 | // List of Regions we'll let clicks through for
187 | var enabledRegions = [ 'mo', 'fl', 'or' ];
188 |
189 | map = jQuery( '#vmap15' ).vectorMap( {
190 | map: 'usa_en',
191 | color: '#007BFF',
192 | borderColor: '#fff',
193 | backgroundColor: '#fff',
194 | enableZoom: true,
195 | showTooltip: true,
196 | selectedColor: '#001BFF',
197 | selectedRegions: [ 'fl' ],
198 | hoverColor: null,
199 | colors: {
200 | mo: '#001BFF',
201 | fl: '#001BFF',
202 | or: '#001BFF'
203 | },
204 | onRegionClick: function ( event, code, region ) {
205 | // Check if this is an Enabled Region, and not the current selected on
206 | if ( enabledRegions.indexOf( code ) === -1 || currentRegion === code ) {
207 | // Not an Enabled Region
208 | event.preventDefault();
209 | } else {
210 | // Enabled Region. Update Newly Selected Region.
211 | currentRegion = code;
212 | }
213 | },
214 | onRegionSelect: function ( event, code, region ) {
215 | console.log( map.selectedRegions );
216 | },
217 | onLabelShow: function ( event, label, code ) {
218 | if ( enabledRegions.indexOf( code ) === -1 ) {
219 | event.preventDefault();
220 | }
221 | }
222 | } );
223 | } );
--------------------------------------------------------------------------------
/static/css/lib/datatable/buttons.bootstrap.min.css:
--------------------------------------------------------------------------------
1 | div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}button.dt-button,div.dt-button,a.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-right:0.333em;padding:0.5em 1em;border:1px solid #999;border-radius:2px;cursor:pointer;font-size:0.88em;color:black;white-space:nowrap;overflow:hidden;background-color:#e9e9e9;background-image:-webkit-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-o-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:linear-gradient(to bottom, #fff 0%, #e9e9e9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled{color:#999;border:1px solid #d0d0d0;cursor:default;background-color:#f9f9f9;background-image:-webkit-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-o-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:linear-gradient(to bottom, #fff 0%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9')}button.dt-button:active:not(.disabled),button.dt-button.active:not(.disabled),div.dt-button:active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button:active:not(.disabled),a.dt-button.active:not(.disabled){background-color:#e2e2e2;background-image:-webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');box-shadow:inset 1px 1px 3px #999999}button.dt-button:active:not(.disabled):hover:not(.disabled),button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button:active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button:active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999999;background-color:#cccccc;background-image:-webkit-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-moz-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-ms-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-o-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:linear-gradient(to bottom, #eaeaea 0%, #ccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc')}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled){border:1px solid #666;background-color:#e0e0e0;background-image:-webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0')}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#79ace9;background-image:-webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-o-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9')}.dt-button embed{outline:none}div.dt-buttons{position:relative;float:left}div.dt-buttons.buttons-right{float:right}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,0.3);z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;display:block;float:none;margin-bottom:4px;margin-right:0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background-image:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');box-shadow:inset 1px 1px 3px #666}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-150px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}
2 |
--------------------------------------------------------------------------------
/static/css/lib/datatable/buttons.dataTables.min.css:
--------------------------------------------------------------------------------
1 | div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}button.dt-button,div.dt-button,a.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-right:0.333em;padding:0.5em 1em;border:1px solid #999;border-radius:2px;cursor:pointer;font-size:0.88em;color:black;white-space:nowrap;overflow:hidden;background-color:#e9e9e9;background-image:-webkit-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-o-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:linear-gradient(to bottom, #fff 0%, #e9e9e9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled{color:#999;border:1px solid #d0d0d0;cursor:default;background-color:#f9f9f9;background-image:-webkit-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-o-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:linear-gradient(to bottom, #fff 0%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9')}button.dt-button:active:not(.disabled),button.dt-button.active:not(.disabled),div.dt-button:active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button:active:not(.disabled),a.dt-button.active:not(.disabled){background-color:#e2e2e2;background-image:-webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');box-shadow:inset 1px 1px 3px #999999}button.dt-button:active:not(.disabled):hover:not(.disabled),button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button:active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button:active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999999;background-color:#cccccc;background-image:-webkit-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-moz-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-ms-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-o-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:linear-gradient(to bottom, #eaeaea 0%, #ccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc')}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled){border:1px solid #666;background-color:#e0e0e0;background-image:-webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0')}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#79ace9;background-image:-webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-o-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9')}.dt-button embed{outline:none}div.dt-buttons{position:relative;float:left}div.dt-buttons.buttons-right{float:right}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,0.3);z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;display:block;float:none;margin-bottom:4px;margin-right:0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background-image:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');box-shadow:inset 1px 1px 3px #666}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-150px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}
2 |
--------------------------------------------------------------------------------
/static/css/cs-skin-elastic.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'icomoon';
3 | src:url('../fonts/icomoon/icomoon.eot?-rdnm34');
4 | src:url('../fonts/icomoon/icomoon.eot?#iefix-rdnm34') format('embedded-opentype'),
5 | url('../fonts/icomoon/icomoon.woff?-rdnm34') format('woff'),
6 | url('../fonts/icomoon/icomoon.ttf?-rdnm34') format('truetype'),
7 | url('../fonts/icomoon/icomoon.svg?-rdnm34#icomoon') format('svg');
8 | font-weight: normal;
9 | font-style: normal;
10 | }
11 |
12 | div.cs-skin-elastic {
13 | background: transparent;
14 | font-size: 1.5em;
15 | font-weight: 700;
16 | color: #5b8583;
17 | }
18 |
19 | @media screen and (max-width: 30em) {
20 | div.cs-skin-elastic { font-size: 1em; }
21 | }
22 |
23 | .cs-skin-elastic > span {
24 | background-color: #fff;
25 | z-index: 100;
26 | }
27 |
28 | .cs-skin-elastic > span::after {
29 | font-family: 'icomoon';
30 | content: '\e005';
31 | -webkit-backface-visibility: hidden;
32 | backface-visibility: hidden;
33 | }
34 |
35 | .cs-skin-elastic .cs-options {
36 | overflow: visible;
37 | background: transparent;
38 | opacity: 1;
39 | visibility: visible;
40 | padding-bottom: 1.25em;
41 | pointer-events: none;
42 | }
43 |
44 | .cs-skin-elastic.cs-active .cs-options {
45 | pointer-events: auto;
46 | }
47 |
48 | .cs-skin-elastic .cs-options > ul::before {
49 | content: '';
50 | position: absolute;
51 | width: 100%;
52 | height: 100%;
53 | left: 0;
54 | top: 0;
55 | -webkit-transform: scale3d(1,0,1);
56 | transform: scale3d(1,0,1);
57 | background: #fff;
58 | -webkit-transform-origin: 50% 0%;
59 | transform-origin: 50% 0%;
60 | -webkit-transition: -webkit-transform 0.3s;
61 | transition: transform 0.3s;
62 | }
63 |
64 | .cs-skin-elastic.cs-active .cs-options > ul::before {
65 | -webkit-transform: scale3d(1,1,1);
66 | transform: scale3d(1,1,1);
67 | -webkit-transition: none;
68 | transition: none;
69 | -webkit-animation: expand 0.6s ease-out;
70 | animation: expand 0.6s ease-out;
71 | }
72 |
73 | .cs-skin-elastic .cs-options ul li {
74 | opacity: 0;
75 | -webkit-transform: translate3d(0,-25px,0);
76 | transform: translate3d(0,-25px,0);
77 | -webkit-transition: opacity 0.15s, -webkit-transform 0.15s;
78 | transition: opacity 0.15s, transform 0.15s;
79 | }
80 |
81 | .cs-skin-elastic.cs-active .cs-options ul li {
82 | -webkit-transform: translate3d(0,0,0);
83 | transform: translate3d(0,0,0);
84 | opacity: 1;
85 | -webkit-transition: none;
86 | transition: none;
87 | -webkit-animation: bounce 0.6s ease-out;
88 | animation: bounce 0.6s ease-out;
89 | }
90 |
91 | /* Optional delays (problematic in IE 11/Win) */
92 | /*
93 | .cs-skin-elastic.cs-active .cs-options ul li:first-child {
94 | -webkit-animation-delay: 0.1s;
95 | animation-delay: 0.1s;
96 | }
97 |
98 | .cs-skin-elastic.cs-active .cs-options ul li:nth-child(2) {
99 | -webkit-animation-delay: 0.15s;
100 | animation-delay: 0.15s;
101 | }
102 |
103 | .cs-skin-elastic.cs-active .cs-options ul li:nth-child(3) {
104 | -webkit-animation-delay: 0.2s;
105 | animation-delay: 0.2s;
106 | }
107 |
108 | .cs-skin-elastic.cs-active .cs-options ul li:nth-child(4) {
109 | -webkit-animation-delay: 0.25s;
110 | animation-delay: 0.25s;
111 | }
112 |
113 | /* with more items, more delays declarations are needed */
114 |
115 |
116 | .cs-skin-elastic .cs-options span {
117 | background-repeat: no-repeat;
118 | background-position: 1.5em 50%;
119 | background-size: 2em auto;
120 | padding: 0.8em 1em 0.8em 4em;
121 | }
122 |
123 | .cs-skin-elastic .cs-options span:hover,
124 | .cs-skin-elastic .cs-options li.cs-focus span,
125 | .cs-skin-elastic .cs-options .cs-selected span {
126 | color: #1e4c4a;
127 | }
128 |
129 | .cs-skin-elastic .cs-options .cs-selected span::after {
130 | content: '';
131 | }
132 |
133 | .cs-skin-elastic .cs-options li.flag-france span {
134 | background-image: url(../img/france.svg);
135 | }
136 |
137 | .cs-skin-elastic .cs-options li.flag-brazil span {
138 | background-image: url(../img/brazil.svg);
139 | }
140 |
141 | .cs-skin-elastic .cs-options li.flag-safrica span {
142 | background-image: url(../img/south-africa.svg);
143 | }
144 |
145 | .cs-skin-elastic .cs-options li.flag-argentina span {
146 | background-image: url(../img/argentina.svg);
147 | }
148 |
149 | @-webkit-keyframes expand {
150 | 0% { -webkit-transform: scale3d(1,0,1); }
151 | 25% { -webkit-transform: scale3d(1,1.2,1); }
152 | 50% { -webkit-transform: scale3d(1,0.85,1); }
153 | 75% { -webkit-transform: scale3d(1,1.05,1) }
154 | 100% { -webkit-transform: scale3d(1,1,1); }
155 | }
156 |
157 | @keyframes expand {
158 | 0% { -webkit-transform: scale3d(1,0,1); transform: scale3d(1,0,1); }
159 | 25% { -webkit-transform: scale3d(1,1.2,1); transform: scale3d(1,1.2,1); }
160 | 50% { -webkit-transform: scale3d(1,0.85,1); transform: scale3d(1,0.85,1); }
161 | 75% { -webkit-transform: scale3d(1,1.05,1); transform: scale3d(1,1.05,1); }
162 | 100% { -webkit-transform: scale3d(1,1,1); transform: scale3d(1,1,1); }
163 | }
164 |
165 |
166 | @-webkit-keyframes bounce {
167 | 0% { -webkit-transform: translate3d(0,-25px,0); opacity:0; }
168 | 25% { -webkit-transform: translate3d(0,10px,0); }
169 | 50% { -webkit-transform: translate3d(0,-6px,0); }
170 | 75% { -webkit-transform: translate3d(0,2px,0); }
171 | 100% { -webkit-transform: translate3d(0,0,0); opacity: 1; }
172 | }
173 |
174 | @keyframes bounce {
175 | 0% { -webkit-transform: translate3d(0,-25px,0); transform: translate3d(0,-25px,0); opacity:0; }
176 | 25% { -webkit-transform: translate3d(0,10px,0); transform: translate3d(0,10px,0); }
177 | 50% { -webkit-transform: translate3d(0,-6px,0); transform: translate3d(0,-6px,0); }
178 | 75% { -webkit-transform: translate3d(0,2px,0); transform: translate3d(0,2px,0); }
179 | 100% { -webkit-transform: translate3d(0,0,0); transform: translate3d(0,0,0); opacity: 1; }
180 | }
181 |
182 |
183 | /* Default custom select styles */
184 | div.cs-select {
185 | display: inline-block;
186 | vertical-align: middle;
187 | position: relative;
188 | text-align: left;
189 | background: #f1f2f7;
190 | z-index: 100;
191 | width: 100%;
192 | max-width: 80px;
193 | margin-left: 25px;
194 | -webkit-touch-callout: none;
195 | -webkit-user-select: none;
196 | -khtml-user-select: none;
197 | -moz-user-select: none;
198 | -ms-user-select: none;
199 | user-select: none;
200 | }
201 |
202 | div.cs-select:focus {
203 | outline: none; /* For better accessibility add a style for this in your skin */
204 | }
205 |
206 | .cs-select select {
207 | display: none;
208 | }
209 |
210 | .cs-select span {
211 | display: block;
212 | position: relative;
213 | cursor: pointer;
214 | padding: 9px 15px;
215 | white-space: nowrap;
216 | overflow: hidden;
217 | text-overflow: ellipsis;
218 | }
219 |
220 | /* Placeholder and selected option */
221 |
222 | .cs-select > span::after,
223 | .cs-select .cs-selected span::after {
224 | speak: none;
225 | position: absolute;
226 | top: 50%;
227 | -webkit-transform: translateY(-50%);
228 | transform: translateY(-50%);
229 | -webkit-font-smoothing: antialiased;
230 | -moz-osx-font-smoothing: grayscale;
231 | }
232 |
233 | .cs-select > span::after {
234 | content: "\f107";
235 | font-family: 'Fontawesome';
236 | right: 1em;
237 | }
238 |
239 | .cs-select .cs-selected span::after {
240 | content: '\2713';
241 | margin-left: 1em;
242 | }
243 |
244 | .cs-select.cs-active > span::after {
245 | -webkit-transform: translateY(-50%) rotate(180deg);
246 | transform: translateY(-50%) rotate(180deg);
247 | }
248 |
249 | div.cs-active {
250 | z-index: 200;
251 | }
252 |
253 | /* Options */
254 | .cs-select .cs-options {
255 | position: absolute;
256 | overflow: hidden;
257 | width: 100%;
258 | background: #f1f2f7;
259 | visibility: hidden;
260 | }
261 |
262 | .cs-select.cs-active .cs-options {
263 | visibility: visible;
264 | }
265 |
266 | .cs-select ul {
267 | list-style: none;
268 | margin: 0;
269 | padding: 0;
270 | width: 100%;
271 | }
272 |
273 | .cs-select ul span {
274 | padding: 5px 15px;
275 | }
276 | .cs-select ul li {
277 | display: block;
278 | }
279 | .cs-select ul li.cs-focus span {
280 | background-color: #ddd;
281 | }
282 |
283 | /* Optgroup and optgroup label */
284 | .cs-select li.cs-optgroup ul {
285 | padding-left: 1em;
286 | }
287 |
288 | .cs-select li.cs-optgroup > span {
289 | cursor: default;
290 | }
291 |
--------------------------------------------------------------------------------
/apps/usuario/views.py:
--------------------------------------------------------------------------------
1 | import json
2 | from django.shortcuts import render, redirect
3 | from django.urls import reverse_lazy
4 | from django.core.serializers import serialize
5 | from django.utils.decorators import method_decorator
6 | from django.views.decorators.cache import never_cache
7 | from django.views.decorators.csrf import csrf_protect
8 | from django.views.generic import View
9 | from django.views.generic.edit import FormView
10 | from django.contrib.auth import login, logout
11 | from django.http import HttpResponseRedirect,HttpResponse,JsonResponse
12 | from django.contrib.auth.mixins import LoginRequiredMixin,PermissionRequiredMixin
13 | from django.views.generic import CreateView, ListView, UpdateView, DeleteView,TemplateView
14 | from apps.usuario.models import Usuario
15 | from apps.usuario.forms import (
16 | FormularioLogin, FormularioUsuario, CambiarPasswordForm
17 | )
18 | from apps.usuario.mixins import (
19 | LoginYSuperStaffMixin, ValidarPermisosMixin, LoginMixin
20 | )
21 |
22 | from apps.libro.models import Libro,Reserva
23 |
24 | class Inicio(LoginRequiredMixin,TemplateView):
25 | """Clase que renderiza el index del sistema"""
26 |
27 | template_name = 'index.html'
28 | groups_required = ['Grupo1','Grupo2']
29 |
30 | def get(self,request,*args,**kwargs):
31 | # SELECT RELATED
32 | """
33 | print(Reserva.objects.select_related().all().query)
34 | reservas = Reserva.objects.select_related().all()
35 | for reserva in reservas:
36 | print(reserva.usuario.username)
37 | print(reserva.libro.titulo)
38 | print(reserva.libro.fecha_publicacion)
39 | """
40 |
41 | # PREFETCH RELATED
42 |
43 | print(Libro.objects.prefetch_related('autor_id').all().query)
44 | print("----------------------------")
45 | libros = Libro.objects.prefetch_related('autor_id').all()
46 | for libro in libros:
47 | print(libro.autor_id.all().query)
48 | for autor in libro.autor_id.all():
49 | print(autor.nombre)
50 | print("----------------------------")
51 | """
52 | contador = 0
53 | grupos_usuario = request.user.groups.all().values('name')
54 | for grupo in grupos_usuario:
55 | if grupo['name'] in self.groups_required:
56 | contador += 1
57 |
58 | if contador == len(self.groups_required):
59 | return render(request,self.template_name)
60 | else:
61 | print("NO ESTA DENTRO DE LOS GRUPOS")
62 | # agregar un permiso
63 | # usuario.user_permissions.add(permiso1,permiso2,...)
64 | # usuario.user_permissions.remove(permiso1,permiso2,...)
65 | # usuario.user_permissions.set([lista_permisos])
66 | # usuario.user_permissions.clear()
67 | """
68 | return render(request,self.template_name)
69 |
70 | class Login(FormView):
71 | template_name = 'login.html'
72 | form_class = FormularioLogin
73 | success_url = reverse_lazy('index')
74 |
75 | @method_decorator(csrf_protect)
76 | @method_decorator(never_cache)
77 | def dispatch(self, request, *args, **kwargs):
78 | if request.user.is_authenticated:
79 | return HttpResponseRedirect(self.get_success_url())
80 | else:
81 | return super(Login, self).dispatch(request, *args, **kwargs)
82 |
83 | def form_valid(self, form):
84 | login(self.request, form.get_user())
85 | return super(Login, self).form_valid(form)
86 |
87 |
88 | def logoutUsuario(request):
89 | logout(request)
90 | return HttpResponseRedirect('/accounts/login/')
91 |
92 |
93 | class InicioUsuarios(LoginYSuperStaffMixin, ValidarPermisosMixin, TemplateView):
94 | template_name='usuarios/listar_usuario.html'
95 | permission_required = ('usuario.view_usuario', 'usuario.add_usuario',
96 | 'usuario.delete_usuario', 'usuario.change_usuario')
97 |
98 |
99 | class ListadoUsuario(LoginYSuperStaffMixin, ValidarPermisosMixin, ListView):
100 | model = Usuario
101 | permission_required = ('usuario.view_usuario', 'usuario.add_usuario',
102 | 'usuario.delete_usuario', 'usuario.change_usuario')
103 |
104 | def get_queryset(self):
105 | return self.model.objects.filter(is_active=True)
106 |
107 | def get(self,request,*args,**kwargs):
108 | if request.is_ajax():
109 | return HttpResponse(serialize('json', self.get_queryset()), 'application/json')
110 | else:
111 | return redirect('usuarios:inicio_usuarios')
112 |
113 |
114 | class RegistrarUsuario(LoginYSuperStaffMixin, ValidarPermisosMixin, CreateView):
115 | model = Usuario
116 | form_class = FormularioUsuario
117 | template_name = 'usuarios/crear_usuario.html'
118 | permission_required = ('usuario.view_usuario', 'usuario.add_usuario',
119 | 'usuario.delete_usuario', 'usuario.change_usuario')
120 |
121 | def post(self, request, *args, **kwargs):
122 | if request.is_ajax():
123 | form = self.form_class(request.POST)
124 | if form.is_valid():
125 | form.save()
126 | mensaje = f'{self.model.__name__} registrado correctamente!'
127 | error = 'No hay error!'
128 | response = JsonResponse({'mensaje':mensaje,'error':error})
129 | response.status_code = 201
130 | return response
131 | else:
132 | mensaje = f'{self.model.__name__} no se ha podido registrar!'
133 | error = form.errors
134 | response = JsonResponse({'mensaje': mensaje, 'error': error})
135 | response.status_code = 400
136 | return response
137 | else:
138 | return redirect('usuarios:inicio_usuarios')
139 |
140 |
141 | class EditarUsuario(LoginYSuperStaffMixin, ValidarPermisosMixin, UpdateView):
142 | model = Usuario
143 | form_class = FormularioUsuario
144 | template_name = 'usuarios/editar_usuario.html'
145 | permission_required = ('usuario.view_usuario', 'usuario.add_usuario',
146 | 'usuario.delete_usuario', 'usuario.change_usuario')
147 |
148 | def post(self,request,*args,**kwargs):
149 | if request.is_ajax():
150 | form = self.form_class(request.POST,instance = self.get_object())
151 | if form.is_valid():
152 | form.save()
153 | mensaje = f'{self.model.__name__} actualizado correctamente!'
154 | error = 'No hay error!'
155 | response = JsonResponse({'mensaje': mensaje, 'error': error})
156 | response.status_code = 201
157 | return response
158 | else:
159 | mensaje = f'{self.model.__name__} no se ha podido actualizar!'
160 | error = form.errors
161 | response = JsonResponse({'mensaje': mensaje, 'error': error})
162 | response.status_code = 400
163 | return response
164 | else:
165 | return redirect('usuarios:inicio_usuarios')
166 |
167 |
168 | class EliminarUsuario(LoginYSuperStaffMixin, ValidarPermisosMixin, DeleteView):
169 | model = Usuario
170 | template_name = 'usuarios/eliminar_usuario.html'
171 | permission_required = ('usuario.view_usuario', 'usuario.add_usuario',
172 | 'usuario.delete_usuario', 'usuario.change_usuario')
173 |
174 | def delete(self,request,*args,**kwargs):
175 | if request.is_ajax():
176 | usuario = self.get_object()
177 | usuario.usuario_activo = False
178 | usuario.save()
179 | mensaje = f'{self.model.__name__} eliminado correctamente!'
180 | error = 'No hay error!'
181 | response = JsonResponse({'mensaje': mensaje, 'error': error})
182 | response.status_code = 201
183 | return response
184 | else:
185 | return redirect('usuarios:inicio_usuarios')
186 |
187 |
188 | class CambiarPassword(LoginMixin, View):
189 | template_name = 'usuarios/cambiar_password.html'
190 | form_class = CambiarPasswordForm
191 | success_url = reverse_lazy('index')
192 |
193 | def get(self, request, *args, **kwargs):
194 | return render(request, self.template_name, {'form': self.form_class})
195 |
196 | def post(self, request, *args, **kwargs):
197 | form = self.form_class(request.POST)
198 | if form.is_valid():
199 | user = Usuario.objects.filter(id=request.user.id)
200 | if user.exists():
201 | user = user.first()
202 | user.set_password(form.cleaned_data.get('password1'))
203 | user.save()
204 | logout(request)
205 | return redirect(self.success_url)
206 | return redirect(self.success_url)
207 | else:
208 | form = self.form_class(request.POST)
209 | return render(request, self.template_name, {'form': form})
210 |
211 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 | {% load has_group %}
3 |
4 |
5 |
6 |
7 |
8 | {% block titulo %}Bienvenido a Biblioteca.dev {% endblock titulo %}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {% block extra_css %}
21 | {% endblock extra_css %}
22 |
23 |
24 |
25 |
26 |
70 |
71 |
72 |
73 |
74 |
98 |
99 |
100 |
101 |
102 |
103 | {% block body %}
104 |
105 |
106 |
107 |
108 | {{ user.username | upper }} BIENVENIDO A BIBLIOTECA.DEV
109 |
110 |
111 |
112 |
113 |
114 | {% endblock body %}
115 |
116 |
117 |
118 |
119 |
120 |
121 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
153 | {% block extrajs %}
154 | {% endblock extrajs %}
155 |
156 |
157 |
--------------------------------------------------------------------------------
/static/fonts/icomoon/icomoon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
31 |
--------------------------------------------------------------------------------