Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
392f42a
Add button and categories
Aug 12, 2023
4dfb050
Changing the actions icon and adding preview
Aug 13, 2023
9906b28
change the comments
Aug 13, 2023
947c0a7
change the title of action and remove the option when touching the title
Aug 14, 2023
ee14c62
change the entry_list
Aug 15, 2023
bacf968
Beta, datatable in the Blog
Aug 19, 2023
7f54399
Add the datatable.
Aug 19, 2023
4a32b61
The datatable is loading the data.
Aug 19, 2023
783a2b3
Delete the author column
Aug 19, 2023
788dccb
Adding the data table with the change in the filter.
Aug 19, 2023
ec3a159
test de datatable
Aug 20, 2023
1f2ee77
add the serializer for author and categories
Aug 20, 2023
e53b16c
falta:
Aug 21, 2023
b78f04b
falta:
Aug 22, 2023
195575f
add the edit in the datatable, blog
Aug 22, 2023
8377f1f
add the update in the blog
Aug 22, 2023
f4b275d
change the fields, datatable
Aug 25, 2023
ad97945
Revert "change the fields, datatable"
Aug 26, 2023
5575f58
add the change in the viewset
Aug 29, 2023
08608d2
version con el actualizar en un modal
Aug 29, 2023
638fed4
Beta final.
Sep 3, 2023
14e1185
Blog funcional
Sep 3, 2023
0ed4427
bug de la ruta del action detail arreglado
Sep 10, 2023
6214b69
arrelgando bug: al seleccionar la fila se enrutaba en lugar de al sel…
Sep 10, 2023
2869d90
falta arreglar el problema con el actualizar
Sep 10, 2023
7a9f46e
beta de blog
Sep 11, 2023
bb58b70
codigo limpio
Sep 11, 2023
3bd31a5
arreglando problema con el title en el modal del eliminar
Sep 12, 2023
33cec10
creando mis pruebas unitarias
Sep 15, 2023
e50a935
validaciones de permisos compeltados
Sep 17, 2023
118c41f
permisos para ver detalles
Sep 18, 2023
54eb45c
Blog permission management
Sep 18, 2023
4fefffe
Add the test in the blog
Sep 19, 2023
5f95686
feature_image in the API
Sep 23, 2023
9b1578f
Add new API
Sep 25, 2023
a2c7d40
Add new api
Sep 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions djgentelella/blog/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from djgentelella.permission_management import AllPermissionByAction, \
AnyPermissionByAction
from objectmanagement import AuthAllPermBaseObjectManagement
from djgentelella.objectmanagement import AuthAllPermBaseObjectManagement


class BaseObjectBlog(AuthAllPermBaseObjectManagement):
Expand All @@ -18,9 +18,9 @@ class BaseObjectBlog(AuthAllPermBaseObjectManagement):
'update': None,
'retrieve': None,
'get_values_for_update': None,
'destroy': None

}

# authentication_classes = (TokenAuthentication, SessionAuthentication)
# queryset =
pagination_class = LimitOffsetPagination
Expand Down
41 changes: 41 additions & 0 deletions djgentelella/blog/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import base64
from django.core.files.base import ContentFile
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

class GTBase64FileField(serializers.Field):
def to_internal_value(self, data):

if not isinstance(data, list):
raise serializers.ValidationError(_("List was expected"))


if len(data) < 1:
raise serializers.ValidationError(
_("List must contain at least one element"))


file_info = data[0]


if not isinstance(file_info, dict) or 'name' not in file_info or 'value' not in file_info:
raise serializers.ValidationError(
_("Invalid structure. You need to provide {name: 'name of file', value: 'base64 string representation'}"))


file_name = file_info['name']
file_value = file_info['value']

try:

decoded_value = base64.b64decode(file_value)
except base64.binascii.Error:
raise serializers.ValidationError(_(
"The 'value' is not a valid base64 string"))

file_content = ContentFile(decoded_value, name=file_name)

return file_content

def to_representation(self, value):
pass
6 changes: 2 additions & 4 deletions djgentelella/blog/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ class Meta:
exclude = ('published_content', 'author')
widgets = {
'title': genwidgets.TextInput,
'content': TextareaWysiwyg,
'resume': TextareaWysiwyg,
'content': genwidgets.Textarea,
'resume': genwidgets.Textarea,
'is_published': genwidgets.YesNoInput,
'categories': genwidgets.SelectMultipleAdd(attrs={
'add_url': reverse_lazy('blog:category_add')
}),

}


class CategoryForm(CustomForm, forms.ModelForm):
class Meta:
model = models.Category
Expand Down
51 changes: 40 additions & 11 deletions djgentelella/blog/templates/gentelella/blog/entry_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,46 @@ <h3 class="heading-1"><span>{% trans 'List of blogs' %}</span></h3>
{{block.super}}
<script>

document.addEventListener("DOMContentLoaded", function () {
tinymce.init({
selector: 'textarea.wysiwyg',
plugins: 'wordcount', // Habilita el complemento de contador de palabras
// Otras configuraciones generales de TinyMCE
});

tinymce.init({
selector: 'textarea#id_create-content',
plugins: 'wordcount', // Configura los complementos que deseas habilitar
// Otras configuraciones de TinyMCE
setup: function (editor) {
editor.on('change', function () {
// Captura el contenido actual del editor
var content = editor.getContent();

// Actualiza el valor del campo de texto en el formulario
document.getElementById('id_create-content').value = content;
});
}
});


tinymce.init({
selector: 'textarea#id_create-resume',
plugins: 'wordcount', // Configura los complementos que deseas habilitar
setup: function (editor) {
editor.on('change', function () {
// Captura el contenido actual del editor
var content = editor.getContent();

// Actualiza el valor del campo de texto en el formulario
document.getElementById('id_create-resume').value = content;
});
}
});

});


var object_urls ={
list_url: "{% url 'api-objectbLog-list' %}",
destroy_url: "{% url 'api-objectbLog-detail' 0 %}",
Expand Down Expand Up @@ -84,9 +124,6 @@ <h3 class="heading-1"><span>{% trans 'List of blogs' %}</span></h3>
create: "#create_obj_modal",
{% endif %}

//update: "#update_obj_modal",


{% if perms.blog.delete_entry %}
destroy: "#delete_obj_modal",
{% endif %}
Expand Down Expand Up @@ -115,10 +152,8 @@ <h3 class="heading-1"><span>{% trans 'List of blogs' %}</span></h3>
'url': null,
'i_class': 'fa fa-edit',
})

{% endif %}


let objconfig={
urls: object_urls,
datatable_element: "#blog_table",
Expand All @@ -133,7 +168,6 @@ <h3 class="heading-1"><span>{% trans 'List of blogs' %}</span></h3>

let ocrud=ObjectCRUD("setmeunique", objconfig)/// setmeunique DISTINTO


ocrud.detailblog = function(row) {
console.log("El row es:", row);
var slug = row.slug;
Expand All @@ -150,11 +184,6 @@ <h3 class="heading-1"><span>{% trans 'List of blogs' %}</span></h3>

ocrud.init();






</script>


Expand Down
2 changes: 1 addition & 1 deletion djgentelella/blog/tests/test_API_blog.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.test import TestCase
from djgentelella.blog.forms import EntryForm, CategoryForm
from djgentelella.blog.models import Entry, Category
from djgentelella.blog.models import Category

class EntryFormTest(TestCase):

Expand Down
7 changes: 6 additions & 1 deletion djgentelella/blog/tests/test_entry_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
class TestEntryDetail(TestCase):

def setUp(self):
self.entry_1 = models.Entry.objects.create(title=u'Welcome!', is_published=True)
self.entry_1 = models.Entry.objects.create(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For fixtures in test you can use factory-boy it will allow you to easy create fixtures and deal with django model dependencies. https://factoryboy.readthedocs.io/en/stable/

title=u'Welcome!',
is_published=True,
content='### Some Content',
resume='This is a resume',
)

self.url = self.entry_1.get_absolute_url()

Expand Down
31 changes: 17 additions & 14 deletions djgentelella/blog/tests/test_entry_forms.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from django.forms import ModelForm
from django.test import TestCase
from django.utils.html import strip_tags # Agrega esta importación

from djgentelella.blog import models


class TestEntryEditing(TestCase):

def setUp(self):
self.entry = models.Entry.objects.create(title=u'Welcome!',
content='### Some Content',
is_published=False)
self.entry = models.Entry.objects.create(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use factory-boy here.

title=u'Welcome!',
content='### Some Content',
is_published=False,
resume='This is a resume',
)

class EntryForm(ModelForm):
class Meta:
model = models.Entry
fields = ['title', 'content', 'is_published']
fields = ['title', 'content', 'is_published', 'resume']

self.form_cls = EntryForm

Expand All @@ -24,25 +27,25 @@ def test_form_editing(self):
'title': 'Last Post (Final)',
'content': '### Goodbye!',
'is_published': True,
'resume': 'Last resume',
}

form = self.form_cls(update, instance=self.entry)

form.save()

actual = models.Entry.objects.get(pk=self.entry.pk)
self.assertEquals(actual.title, update['title'])
self.assertEquals(actual.content.raw, update['content'])
self.assertEqual(actual.title, update['title'])
self.assertEqual(actual.content.raw, update['content'])
self.assertIsNotNone(actual.published_timestamp)

self.assertEqual(strip_tags(actual.resume.rendered), update['resume']) # Comparar con rendered sin etiquetas HTML

class TestEntryCreation(TestCase):

def setUp(self):
class EntryForm(ModelForm):
class Meta:
model = models.Entry
fields = ['title', 'content', 'is_published']
fields = ['title', 'content', 'is_published', 'resume']

self.form_cls = EntryForm

Expand All @@ -52,14 +55,14 @@ def test_form_create(self):
'title': 'Last Post (Final)',
'content': '### Goodbye!',
'is_published': False,
'resume': 'Last resume',
}

form = self.form_cls(create)
print(form.errors)

form.save()

actual = models.Entry.objects.get(slug='last-post-final')
self.assertEquals(actual.title, create['title'])
self.assertEquals(actual.content.raw, create['content'])
self.assertEqual(actual.title, create['title'])
self.assertEqual(actual.content.raw, create['content'])
self.assertIsNone(actual.published_timestamp)
self.assertEqual(strip_tags(actual.resume.rendered), create['resume']) # Comparar con rendered sin etiquetas HTML
2 changes: 0 additions & 2 deletions djgentelella/blog/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
from . import views

from djgentelella.datatables.api import BlogViewSet

from djgentelella.blog.views import object_blog
from djgentelella.blog.viewset import ObjectBLog

from demoapp.cruds import Personclass


Expand Down
11 changes: 4 additions & 7 deletions djgentelella/blog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@
from django.utils.translation import gettext_lazy as _
from django.views.generic import ListView, DetailView, CreateView, UpdateView, \
DeleteView

from . import models
from .forms import EntryForm, CategoryForm
from .models import Category


from djgentelella.blog.forms import EntryForm
from django.urls import reverse

Expand All @@ -38,10 +35,10 @@ def get_context_data(self, **kwargs):
context['q'] = self.request.GET.get('q', '')
context['entry'] = models.Entry.objects.first()
context['create_form'] = EntryForm(prefix='create')

return context



class EntryDetail(DetailView):
model = models.Entry
template_name = 'gentelella/blog/entry_detail.html'
Expand All @@ -60,21 +57,21 @@ def get_context_data(self, **kwargs):
return context




class EntryCreate(PermissionRequiredMixin, CreateView):
permission_required = 'blog.add_entry'
model = models.Entry
template_name = 'gentelella/blog/entry_form.html'
success_url = reverse_lazy('blog:entrylist')
form_class = EntryForm


def form_valid(self, form):
response = super().form_valid(form)
publishbtn = self.request.POST.get('publishbtn', '') == 'publish'
if publishbtn:
self.object.is_published = True

self.object.content = form.cleaned_data['content']

if self.object.is_published and publishbtn:
self.object.published_content = self.object.content.rendered
if self.object.author is None:
Expand Down
18 changes: 10 additions & 8 deletions djgentelella/blog/viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ class ObjectBLog(BaseObjectBlog):
'create': serializer.BlogCreateSerializer,
'update': serializer.BlogCreateSerializer,
'retrieve': serializer.BlogUpdateSerializer,
'get_values_for_update': serializer.BlogUpdateSerializer
'get_values_for_update': serializer.BlogUpdateSerializer,
'destroy': serializer.BlogDestroySerializer
}

perms = {
'list': ['blog.view_entry'],
'create': ['blog.add_category', 'blog.add_entry', 'blog.add_entry_image'],
'update': ['blog.change_category', 'blog.change_entry', 'blog.change_entry_image'],
'retrieve': ['blog.view_entry', 'blog.view_category', 'blog.view_entry_image'],
'get_values_for_update': ['blog.view_entry'],
'destroy': ['blog.delete_entry_image', 'blog.delete_category', 'blog.delete_entry']
'list': ['blog.view_entry', 'blog.view_entry_image', 'blog.view_category'],
'create': ['blog.add_entry', 'blog.add_entry_image', 'blog.add_category'],
'update': ['blog.change_entry', 'blog.change_entry_image', 'blog.change_category'],
'retrieve': ['blog.view_entry', 'blog.view_entry_image', 'blog.view_category'],
'get_values_for_update': ['blog.view_entry', 'blog.view_entry_image', 'blog.view_category'],
'destroy': ['blog.delete_entry', 'blog.delete_entry_image', 'blog.delete_category']
}
#Asigna el author al usuario actual

def perform_create(self, serializer): # ESTO ASIGNA EL author
serializer.save(author=self.request.user)
self.operation_type = 'create'
Expand Down
Loading