From 5812975c480ba11cb7352861d2a63ed66e0276a5 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 14:53:48 -0300 Subject: [PATCH 01/51] gitignore: putting media --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 28a3e865..fbd63a05 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ __pycache__/ local_settings.py db.sqlite3 db.sqlite3-journal +media # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ # in your Git repository. Update and uncomment the following line accordingly. From 1965d7d1882d184e629cb3d1776a99acc73074a5 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 14:54:40 -0300 Subject: [PATCH 02/51] fix: specifying databse in local and production env --- forunb/forunb/settings/local.py | 2 ++ forunb/main/models.py | 9 +++++++-- forunb/users/models.py | 9 ++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/forunb/forunb/settings/local.py b/forunb/forunb/settings/local.py index c30f208c..fd2167d3 100644 --- a/forunb/forunb/settings/local.py +++ b/forunb/forunb/settings/local.py @@ -12,3 +12,5 @@ 'NAME': BASE_DIR / 'db.sqlite3', } } + +DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' diff --git a/forunb/main/models.py b/forunb/main/models.py index e0a89849..9e345e19 100644 --- a/forunb/main/models.py +++ b/forunb/main/models.py @@ -6,6 +6,11 @@ from users.models import CustomUser from cloudinary.models import CloudinaryField +if settings.DEBUG: + ImageField = models.ImageField +else: + from cloudinary.models import CloudinaryField + ImageField = CloudinaryField class Forum(models.Model): """Model for a forum.""" @@ -53,7 +58,7 @@ class Question(Post): default=0, verbose_name='Favorited Count' ) is_anonymous = models.BooleanField(default=False, verbose_name='') - image = CloudinaryField('image', blank=True, null=True) + image = ImageField('image', blank=True, null=True) upvoters = models.ManyToManyField( settings.AUTH_USER_MODEL, related_name='upvoted_questions', blank=True ) @@ -100,7 +105,7 @@ class Answer(Post): is_anonymous = models.BooleanField( default=False, verbose_name='Modo anônimo' ) - image = CloudinaryField('image', blank=True, null=True) + image = ImageField('image', blank=True, null=True) upvoters = models.ManyToManyField( settings.AUTH_USER_MODEL, related_name='upvoted_answers', blank=True ) diff --git a/forunb/users/models.py b/forunb/users/models.py index ed268d87..77fa7b38 100644 --- a/forunb/users/models.py +++ b/forunb/users/models.py @@ -3,6 +3,13 @@ from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from cloudinary.models import CloudinaryField +from django.conf import settings + +if settings.DEBUG: + ImageField = models.ImageField +else: + from cloudinary.models import CloudinaryField + ImageField = CloudinaryField class CustomUserManager(BaseUserManager): @@ -30,7 +37,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) username = models.CharField(max_length=100, unique=True, blank=True, null=True) - photo = CloudinaryField('image', blank=True, null=True) + photo = ImageField('image', blank=True, null=True) # photo = models.ImageField(upload_to='media/profile_pics/', blank=True, null=True) Usar Localmente!!!! followed_forums = models.ManyToManyField('main.Forum', blank=True, related_name='followers') liked_answers = models.ManyToManyField('main.Answer', blank=True, related_name='liked_by') From 7b3da044d5e57dbf66d14e1470183ccad567e11e Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 15:27:05 -0300 Subject: [PATCH 03/51] html: Changing images proportions --- forunb/main/templates/main/new_question.html | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/forunb/main/templates/main/new_question.html b/forunb/main/templates/main/new_question.html index 39ba50d1..feb735cc 100644 --- a/forunb/main/templates/main/new_question.html +++ b/forunb/main/templates/main/new_question.html @@ -31,7 +31,7 @@

Perguntar em {{ forum.title }}

-
+
@@ -129,8 +129,7 @@

Perguntar em {{ forum.title }}

function showCropper(event) { const files = event.target.files; - const imgContainer = document.querySelector('.img-container'); // Seleciona a área de visualização da imagem - const imgPreview = document.querySelector('.img-preview'); // Seleciona a pré-visualização da imagem + const imgContainer = document.querySelector('.img-container'); if (files && files.length > 0) { const file = files[0]; @@ -149,20 +148,18 @@

Perguntar em {{ forum.title }}

cropper.destroy(); } cropper = new Cropper(image, { - aspectRatio: 1, + aspectRatio: NaN, // Liberdade para escolher a proporção viewMode: 1, - preview: '.img-preview', }); imgContainer.style.display = 'block'; // Mostra a área de visualização da imagem - imgPreview.style.display = 'block'; // Mostra a pré-visualização da imagem }; reader.readAsDataURL(file); } else { imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem - imgPreview.style.display = 'none'; // Esconde a pré-visualização da imagem } } + function submitForm(event) { event.preventDefault(); const form = event.target; @@ -215,7 +212,7 @@

Perguntar em {{ forum.title }}

// Oculta a área de visualização da imagem document.querySelector('.img-container').style.display = 'none'; - document.querySelector('.img-preview').style.display = 'none'; + //document.querySelector('.img-preview').style.display = 'none'; // Remove a imagem de pré-visualização document.getElementById('cropper-image').src = ''; From 6c373f041993168460fdbfdb5d0d7e1a3d6a4f4f Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 16:06:42 -0300 Subject: [PATCH 04/51] css: Fixing images proportions --- forunb/static/css/styles.css | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/forunb/static/css/styles.css b/forunb/static/css/styles.css index 069a6b8b..30d4694b 100644 --- a/forunb/static/css/styles.css +++ b/forunb/static/css/styles.css @@ -636,8 +636,12 @@ html, body { } .img-question { - min-height: 400px; - max-width: 400px; + max-width: 700px; /* A largura máxima da imagem será 700px */ + min-height: 300px; + max-height: 400px; /* A altura máxima da imagem será 400px */ + width: auto; /* A largura se ajusta automaticamente para manter a proporção */ + height: auto; /* A altura se ajusta automaticamente para manter a proporção */ + display: block; /* Garante que a imagem seja um bloco e respeite o dimensionamento */ } @media (max-width: 767px) { From 519a44a91cd62e5a3557e4a1c7122dcbebffa415 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 16:22:40 -0300 Subject: [PATCH 05/51] refactor: Fixing login_required in views --- forunb/main/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forunb/main/views.py b/forunb/main/views.py index 0162ff50..345855ec 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -192,7 +192,7 @@ def notifications(request): return render(request, 'main/notifications.html', {'notifications': user_notifications}) -@login_required +@login_required(login_url='/users/login') @require_POST def toggle_upvote_question(request, question_id): """Toggle the upvote of a question for a user.""" @@ -201,7 +201,7 @@ def toggle_upvote_question(request, question_id): return JsonResponse({'upvotes': question.upvote_count}) -@login_required +@login_required(login_url='/users/login') @require_POST def toggle_upvote_answer(request, answer_id): """Toggle the upvote of an answer for a user.""" From 9c64f81a572e78b6fb0313375a6d6014794b8b21 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 16:51:32 -0300 Subject: [PATCH 06/51] Fix: Fixing bug notifications don't saving --- forunb/main/templates/main/question_detail.html | 4 +++- forunb/main/views.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/forunb/main/templates/main/question_detail.html b/forunb/main/templates/main/question_detail.html index 92b428aa..7acc2d66 100644 --- a/forunb/main/templates/main/question_detail.html +++ b/forunb/main/templates/main/question_detail.html @@ -513,11 +513,13 @@

Denunciar

function showReportForm(itemId, itemType) { const form = document.getElementById('reportForm'); - form.action = "{% url 'main:report' 0 1 %}".replace('0', itemId).replace('1', itemType); + const actionUrl = `/report/${itemId}/${itemType}/`; + form.action = actionUrl; document.getElementById("reportType").textContent = itemType === 'question' ? 'Pergunta' : 'Resposta'; document.getElementById("reportModal").style.display = "block"; } + function closeReportForm() { document.getElementById("reportModal").style.display = "none"; } diff --git a/forunb/main/views.py b/forunb/main/views.py index 345855ec..b95ed1b8 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -232,6 +232,7 @@ def report(request, item_id, item_type): report_instance.user = request.user report_instance.save() return JsonResponse({'success': True}) + print(form.errors) # Isso irá mostrar quais campos estão falhando return JsonResponse({'success': False, 'errors': form.errors.as_json()}) return JsonResponse({'success': False, 'error': 'Método não permitido.'}, status=405) except Exception as e: # pylint: disable=broad-except From 368d2045d6af856a217b57a8af1582d66ee3a840 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 17:07:03 -0300 Subject: [PATCH 07/51] html: Fixing images proportion in answers --- forunb/main/templates/main/question_detail.html | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/forunb/main/templates/main/question_detail.html b/forunb/main/templates/main/question_detail.html index 7acc2d66..e9c4a315 100644 --- a/forunb/main/templates/main/question_detail.html +++ b/forunb/main/templates/main/question_detail.html @@ -103,7 +103,7 @@

Denunciar

-
+
@@ -343,14 +343,15 @@

Denunciar

function showCropper(event) { const files = event.target.files; - const imgContainer = document.querySelector('.img-container'); // Seleciona a área de visualização da imagem - const imgPreview = document.querySelector('.img-preview'); // Seleciona a pré-visualização da imagem + const imgContainer = document.querySelector('.img-container'); + if (files && files.length > 0) { const file = files[0]; const validImageTypes = ['image/jpeg', 'image/png', 'image/gif']; if (!validImageTypes.includes(file.type)) { alert('Por favor, selecione uma imagem válida (JPEG, PNG, GIF).'); event.target.value = ''; // Limpa o input + imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem return; } @@ -361,20 +362,17 @@

Denunciar

cropper.destroy(); } cropper = new Cropper(image, { - aspectRatio: 1, + aspectRatio: NaN, // Liberdade para escolher a proporção viewMode: 1, - preview: '.img-preview', }); imgContainer.style.display = 'block'; // Mostra a área de visualização da imagem - imgPreview.style.display = 'block'; }; reader.readAsDataURL(file); } else { imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem - imgPreview.style.display = 'none'; // Esconde a pré-visualização da imagem } } - + function submitForm(event) { event.preventDefault(); const form = event.target; @@ -452,7 +450,7 @@

Denunciar

} const imgContainer = document.querySelector('.img-container'); - const imgPreview = document.querySelector('.img-preview'); + //const imgPreview = document.querySelector('.img-preview'); const cropperImage = document.getElementById('cropper-image'); if (imgContainer && imgPreview && cropperImage) { From a6240e85efb2f14e7bb20115523f88dc8f4d00c9 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 17:38:32 -0300 Subject: [PATCH 08/51] settings: Adding staticfile_storage in production --- forunb/forunb/settings/production.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forunb/forunb/settings/production.py b/forunb/forunb/settings/production.py index faa62f39..a1b53965 100644 --- a/forunb/forunb/settings/production.py +++ b/forunb/forunb/settings/production.py @@ -25,3 +25,5 @@ DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage' MEDIA_URL = 'https://res.cloudinary.com/dmezdx5mc/image/upload/' + +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' From 6bdab2bae58655cdf8d72e6cb0b5cfad2fa674fc Mon Sep 17 00:00:00 2001 From: manu-sgc Date: Fri, 23 Aug 2024 22:05:26 -0300 Subject: [PATCH 09/51] fix: adjusting picture's proporcionality --- forunb/static/css/styles.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/forunb/static/css/styles.css b/forunb/static/css/styles.css index 30d4694b..32e2fcec 100644 --- a/forunb/static/css/styles.css +++ b/forunb/static/css/styles.css @@ -642,12 +642,14 @@ html, body { width: auto; /* A largura se ajusta automaticamente para manter a proporção */ height: auto; /* A altura se ajusta automaticamente para manter a proporção */ display: block; /* Garante que a imagem seja um bloco e respeite o dimensionamento */ + object-fit: contain; } @media (max-width: 767px) { .img-question{ min-height: 300px; - max-width: 300px; + max-width: 400px; + object-fit: contain; } } From 063bb7bdae78f017b5a632a6e41550b69c36f576 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Fri, 23 Aug 2024 23:52:56 -0300 Subject: [PATCH 10/51] css: alying img-question object-position in left center --- forunb/static/css/styles.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forunb/static/css/styles.css b/forunb/static/css/styles.css index 32e2fcec..67ee01a4 100644 --- a/forunb/static/css/styles.css +++ b/forunb/static/css/styles.css @@ -643,6 +643,7 @@ html, body { height: auto; /* A altura se ajusta automaticamente para manter a proporção */ display: block; /* Garante que a imagem seja um bloco e respeite o dimensionamento */ object-fit: contain; + object-position: left center; } @media (max-width: 767px) { @@ -650,6 +651,7 @@ html, body { min-height: 300px; max-width: 400px; object-fit: contain; + object-position: left center; } } From 7084eec92503b2e6a76ac17b782132aeb6ab6805 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 12:05:53 -0300 Subject: [PATCH 11/51] html: getting data log --- forunb/main/templates/main/new_question.html | 1 + 1 file changed, 1 insertion(+) diff --git a/forunb/main/templates/main/new_question.html b/forunb/main/templates/main/new_question.html index feb735cc..36245bf0 100644 --- a/forunb/main/templates/main/new_question.html +++ b/forunb/main/templates/main/new_question.html @@ -189,6 +189,7 @@

Perguntar em {{ forum.title }}

}) .then(response => response.json()) .then(data => { + console.log(data); document.getElementById('loading-spinner').style.display = 'none'; if (data.success) { window.location.href = `{% url 'main:question_detail' 0 %}`.replace('0', data.question_id); From 1dd72b85768b94e28afe2ad6fb72ae3549393eca Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 12:29:26 -0300 Subject: [PATCH 12/51] Host: Testig debug true --- forunb/forunb/settings/production.py | 2 +- forunb/main/models.py | 2 +- forunb/users/models.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/forunb/forunb/settings/production.py b/forunb/forunb/settings/production.py index a1b53965..8553dbc3 100644 --- a/forunb/forunb/settings/production.py +++ b/forunb/forunb/settings/production.py @@ -8,7 +8,7 @@ # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = True ALLOWED_HOSTS = ['.herokuapp.com', '.forunb.com'] diff --git a/forunb/main/models.py b/forunb/main/models.py index 9e345e19..87b50c7f 100644 --- a/forunb/main/models.py +++ b/forunb/main/models.py @@ -7,7 +7,7 @@ from cloudinary.models import CloudinaryField if settings.DEBUG: - ImageField = models.ImageField + ImageField = CloudinaryField else: from cloudinary.models import CloudinaryField ImageField = CloudinaryField diff --git a/forunb/users/models.py b/forunb/users/models.py index 77fa7b38..3324f74e 100644 --- a/forunb/users/models.py +++ b/forunb/users/models.py @@ -6,7 +6,7 @@ from django.conf import settings if settings.DEBUG: - ImageField = models.ImageField + ImageField = CloudinaryField else: from cloudinary.models import CloudinaryField ImageField = CloudinaryField From 997825bbb5c4146ee8e0ee67e94c52ba81a5de35 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 12:37:48 -0300 Subject: [PATCH 13/51] host: returning to early state and depuring --- forunb/forunb/settings/production.py | 2 +- forunb/main/models.py | 2 +- forunb/main/views.py | 9 +++++++-- forunb/users/models.py | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/forunb/forunb/settings/production.py b/forunb/forunb/settings/production.py index 8553dbc3..a1b53965 100644 --- a/forunb/forunb/settings/production.py +++ b/forunb/forunb/settings/production.py @@ -8,7 +8,7 @@ # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = False ALLOWED_HOSTS = ['.herokuapp.com', '.forunb.com'] diff --git a/forunb/main/models.py b/forunb/main/models.py index 87b50c7f..9e345e19 100644 --- a/forunb/main/models.py +++ b/forunb/main/models.py @@ -7,7 +7,7 @@ from cloudinary.models import CloudinaryField if settings.DEBUG: - ImageField = CloudinaryField + ImageField = models.ImageField else: from cloudinary.models import CloudinaryField ImageField = CloudinaryField diff --git a/forunb/main/views.py b/forunb/main/views.py index b95ed1b8..43befeef 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -116,20 +116,25 @@ def follow_forum(request, forum_id, action): @login_required(login_url='/users/login') def new_question(request, forum_id): - """Create a new question.""" + print("Entrou na view new_question") # Depuração forum = get_object_or_404(Forum, id=forum_id) if request.method == 'POST': + print("Método POST detectado") # Depuração form = QuestionForm(request.POST, request.FILES) if form.is_valid(): + print("Formulário válido") # Depuração question = form.save(commit=False) question.forum = forum question.author = request.user question.description = clean_html(question.description) question.save() request.user.created_questions.add(question) + print("Pergunta salva com sucesso") # Depuração return JsonResponse({'success': True, 'question_id': question.id}) + else: + print("Formulário inválido", form.errors) # Depuração return JsonResponse({'success': False, 'errors': form.errors.as_json()}) - + print("Método GET ou outro não permitido") # Depuração form = QuestionForm() return render(request, 'main/new_question.html', {'form': form, 'forum': forum}) diff --git a/forunb/users/models.py b/forunb/users/models.py index 3324f74e..77fa7b38 100644 --- a/forunb/users/models.py +++ b/forunb/users/models.py @@ -6,7 +6,7 @@ from django.conf import settings if settings.DEBUG: - ImageField = CloudinaryField + ImageField = models.ImageField else: from cloudinary.models import CloudinaryField ImageField = CloudinaryField From 6733dd64fd6ca7fba88ad2c209b11219f5754eca Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 12:55:08 -0300 Subject: [PATCH 14/51] host: Depuring --- forunb/main/views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/forunb/main/views.py b/forunb/main/views.py index 43befeef..b8476e8e 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -97,8 +97,12 @@ def question_detail(request, question_id): def clean_html(text): """Remove HTML tags from a text.""" + print("Texto recebido pelo clean_html:", text) # Depuração soup = BeautifulSoup(text, 'html.parser') - return soup.get_text() + cleaned_text = soup.get_text() + print("Texto após limpeza:", cleaned_text) # Depuração + return cleaned_text + @login_required(login_url='/users/login') @@ -128,8 +132,8 @@ def new_question(request, forum_id): question.author = request.user question.description = clean_html(question.description) question.save() - request.user.created_questions.add(question) print("Pergunta salva com sucesso") # Depuração + request.user.created_questions.add(question) return JsonResponse({'success': True, 'question_id': question.id}) else: print("Formulário inválido", form.errors) # Depuração From 95c7e519db04faa6948b6108c4f8ef2ce6330c79 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 13:08:47 -0300 Subject: [PATCH 15/51] host: testing depuring --- forunb/main/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forunb/main/models.py b/forunb/main/models.py index 9e345e19..bc902baa 100644 --- a/forunb/main/models.py +++ b/forunb/main/models.py @@ -74,12 +74,12 @@ def save(self, *args, **kwargs): """Save method for a question.""" super().save(*args, **kwargs) - if self.image: + """if self.image: img = Image.open(self.image.path) # pylint: disable=E1101 if img.height > 800 or img.width > 800: output_size = (800, 800) img.thumbnail(output_size) - img.save(self.image.path) # pylint: disable=E1101 + img.save(self.image.path) # pylint: disable=E1101""" def toggle_upvote(self, user): """Toggles the upvote of a question for a user.""" From 41109aef6b0d5371fba15b189caa0e32c2335642 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 13:46:24 -0300 Subject: [PATCH 16/51] host: fixing creating answers problem --- forunb/main/models.py | 4 ++-- forunb/main/views.py | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/forunb/main/models.py b/forunb/main/models.py index bc902baa..c1bb701b 100644 --- a/forunb/main/models.py +++ b/forunb/main/models.py @@ -122,12 +122,12 @@ def save(self, *args, **kwargs): """Save method for an answer.""" super().save(*args, **kwargs) - if self.image: + """if self.image: img = Image.open(self.image.path) # pylint: disable=E1101 if img.height > 800 or img.width > 800: output_size = (800, 800) img.thumbnail(output_size) - img.save(self.image.path) # pylint: disable=E1101 + img.save(self.image.path) # pylint: disable=E1101""" def toggle_upvote(self, user): """Toggles the upvote of an answer for a user.""" diff --git a/forunb/main/views.py b/forunb/main/views.py index b8476e8e..23f7b5bc 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -120,25 +120,19 @@ def follow_forum(request, forum_id, action): @login_required(login_url='/users/login') def new_question(request, forum_id): - print("Entrou na view new_question") # Depuração + """Create a new question""" forum = get_object_or_404(Forum, id=forum_id) if request.method == 'POST': - print("Método POST detectado") # Depuração form = QuestionForm(request.POST, request.FILES) if form.is_valid(): - print("Formulário válido") # Depuração question = form.save(commit=False) question.forum = forum question.author = request.user question.description = clean_html(question.description) question.save() - print("Pergunta salva com sucesso") # Depuração request.user.created_questions.add(question) return JsonResponse({'success': True, 'question_id': question.id}) - else: - print("Formulário inválido", form.errors) # Depuração return JsonResponse({'success': False, 'errors': form.errors.as_json()}) - print("Método GET ou outro não permitido") # Depuração form = QuestionForm() return render(request, 'main/new_question.html', {'form': form, 'forum': forum}) From 2e4c0ad3f811d563d6860c9e4e0bc1dc62832032 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 14:34:17 -0300 Subject: [PATCH 17/51] test: Updating users/model_tests --- forunb/users/models.py | 12 ++++++------ forunb/users/tests/test_models.py | 25 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/forunb/users/models.py b/forunb/users/models.py index 77fa7b38..5d16d5c7 100644 --- a/forunb/users/models.py +++ b/forunb/users/models.py @@ -5,11 +5,11 @@ from cloudinary.models import CloudinaryField from django.conf import settings -if settings.DEBUG: - ImageField = models.ImageField -else: - from cloudinary.models import CloudinaryField - ImageField = CloudinaryField +def get_image_field(): + if settings.DEBUG: + return models.ImageField + else: + return CloudinaryField class CustomUserManager(BaseUserManager): @@ -37,7 +37,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) username = models.CharField(max_length=100, unique=True, blank=True, null=True) - photo = ImageField('image', blank=True, null=True) + photo = get_image_field()('image', blank=True, null=True) # photo = models.ImageField(upload_to='media/profile_pics/', blank=True, null=True) Usar Localmente!!!! followed_forums = models.ManyToManyField('main.Forum', blank=True, related_name='followers') liked_answers = models.ManyToManyField('main.Answer', blank=True, related_name='liked_by') diff --git a/forunb/users/tests/test_models.py b/forunb/users/tests/test_models.py index f2879d7d..2a85d93c 100644 --- a/forunb/users/tests/test_models.py +++ b/forunb/users/tests/test_models.py @@ -1,7 +1,11 @@ """ Tests for the CustomUser model """ -from django.test import TestCase +from django.test import TestCase, override_settings from users.models import CustomUser from main.models import Forum, Question, Answer, Notification, Report +from cloudinary.models import CloudinaryField +from users.models import CustomUser +from django.db import models +from users.models import get_image_field class CustomUserModelTest(TestCase): @@ -22,12 +26,31 @@ def setUp(self): question=self.question, text='Test Answer', author=self.user ) + @override_settings(DEBUG=False) + def test_get_image_field_in_production(self): + """Test that get_image_field returns CloudinaryField when DEBUG is False.""" + image_field = get_image_field() + self.assertEqual(image_field, CloudinaryField) + + @override_settings(DEBUG=True) + def test_get_image_field_in_debug(self): + """Test that get_image_field returns models.ImageField when DEBUG is True.""" + image_field = get_image_field() + self.assertEqual(image_field, models.ImageField) + def test_create_user(self): """ Test that a user can be created """ self.assertEqual(self.user.email, 'testuser@aluno.unb.br') self.assertTrue(self.user.check_password('password123')) self.assertFalse(self.user.is_staff) + def test_create_user_without_email(self): + """Test that creating a user without an email raises a ValueError.""" + with self.assertRaises(ValueError) as context: + CustomUser.objects.create_user(email=None, password='password123') + + self.assertEqual(str(context.exception), 'The Email field must be set') + def test_create_superuser(self): """ Test that a superuser can be created """ admin_user = CustomUser.objects.create_superuser( From ca927886ac8cfff39729fa05a8db4e1992695cb6 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 14:51:22 -0300 Subject: [PATCH 18/51] refactor: Cleaning duplications --- forunb/main/templates/main/new_question.html | 54 +----------------- .../main/templates/main/question_detail.html | 51 ----------------- forunb/static/js/scripts.js | 55 +++++++++++++++++++ forunb/templates/base.html | 1 + 4 files changed, 57 insertions(+), 104 deletions(-) create mode 100644 forunb/static/js/scripts.js diff --git a/forunb/main/templates/main/new_question.html b/forunb/main/templates/main/new_question.html index 36245bf0..229b7e89 100644 --- a/forunb/main/templates/main/new_question.html +++ b/forunb/main/templates/main/new_question.html @@ -125,59 +125,7 @@

Perguntar em {{ forum.title }}

}); let cropper; -const image = document.getElementById('cropper-image'); - -function showCropper(event) { - const files = event.target.files; - const imgContainer = document.querySelector('.img-container'); - - if (files && files.length > 0) { - const file = files[0]; - const validImageTypes = ['image/jpeg', 'image/png', 'image/gif']; - if (!validImageTypes.includes(file.type)) { - alert('Por favor, selecione uma imagem válida (JPEG, PNG, GIF).'); - event.target.value = ''; // Limpa o input - imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem - return; - } - - const reader = new FileReader(); - reader.onload = function (e) { - image.src = e.target.result; - if (cropper) { - cropper.destroy(); - } - cropper = new Cropper(image, { - aspectRatio: NaN, // Liberdade para escolher a proporção - viewMode: 1, - }); - imgContainer.style.display = 'block'; // Mostra a área de visualização da imagem - }; - reader.readAsDataURL(file); - } else { - imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem - } -} - - - function submitForm(event) { - event.preventDefault(); - const form = event.target; - document.getElementById('loading-spinner').style.display = 'block'; - - const formData = new FormData(form); - - if (cropper && document.getElementById('image').files.length > 0) { - cropper.getCroppedCanvas().toBlob((blob) => { - const fileName = 'cropped_image.png'; - const croppedImage = new File([blob], fileName, { type: 'image/png' }); - formData.append('image', croppedImage); - sendFormData(form.action, formData); - }, 'image/png'); - } else { - sendFormData(form.action, formData); - } - } + const image = document.getElementById('cropper-image'); function sendFormData(url, formData) { fetch(url, { diff --git a/forunb/main/templates/main/question_detail.html b/forunb/main/templates/main/question_detail.html index e9c4a315..193721c4 100644 --- a/forunb/main/templates/main/question_detail.html +++ b/forunb/main/templates/main/question_detail.html @@ -341,57 +341,6 @@

Denunciar

let cropper; const image = document.getElementById('cropper-image'); - function showCropper(event) { - const files = event.target.files; - const imgContainer = document.querySelector('.img-container'); - - if (files && files.length > 0) { - const file = files[0]; - const validImageTypes = ['image/jpeg', 'image/png', 'image/gif']; - if (!validImageTypes.includes(file.type)) { - alert('Por favor, selecione uma imagem válida (JPEG, PNG, GIF).'); - event.target.value = ''; // Limpa o input - imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem - return; - } - - const reader = new FileReader(); - reader.onload = function (e) { - image.src = e.target.result; - if (cropper) { - cropper.destroy(); - } - cropper = new Cropper(image, { - aspectRatio: NaN, // Liberdade para escolher a proporção - viewMode: 1, - }); - imgContainer.style.display = 'block'; // Mostra a área de visualização da imagem - }; - reader.readAsDataURL(file); - } else { - imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem - } - } - - function submitForm(event) { - event.preventDefault(); - const form = event.target; - document.getElementById('loading-spinner').style.display = 'block'; - - const formData = new FormData(form); - - if (cropper && document.getElementById('image').files.length > 0) { - cropper.getCroppedCanvas().toBlob((blob) => { - const fileName = 'cropped_image.png'; - const croppedImage = new File([blob], fileName, { type: 'image/png' }); - formData.append('image', croppedImage); - sendFormData(form.action, formData); - }, 'image/png'); - } else { - sendFormData(form.action, formData); - } - } - function sendFormData(url, formData) { fetch(url, { method: 'POST', diff --git a/forunb/static/js/scripts.js b/forunb/static/js/scripts.js new file mode 100644 index 00000000..63c6cb30 --- /dev/null +++ b/forunb/static/js/scripts.js @@ -0,0 +1,55 @@ +// static/js/scripts.js + +//CROPPER IMAGES FUNCTIONS +function showCropper(event) { + const files = event.target.files; + const imgContainer = document.querySelector('.img-container'); + + if (files && files.length > 0) { + const file = files[0]; + const validImageTypes = ['image/jpeg', 'image/png', 'image/gif']; + if (!validImageTypes.includes(file.type)) { + alert('Por favor, selecione uma imagem válida (JPEG, PNG, GIF).'); + event.target.value = ''; // Limpa o input + imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem + return; + } + + const reader = new FileReader(); + reader.onload = function (e) { + image.src = e.target.result; + if (cropper) { + cropper.destroy(); + } + cropper = new Cropper(image, { + aspectRatio: NaN, // Liberdade para escolher a proporção + viewMode: 1, + }); + imgContainer.style.display = 'block'; // Mostra a área de visualização da imagem + }; + reader.readAsDataURL(file); + } else { + imgContainer.style.display = 'none'; // Esconde a área de visualização da imagem + } +} + +function submitForm(event) { + event.preventDefault(); + const form = event.target; + document.getElementById('loading-spinner').style.display = 'block'; + + const formData = new FormData(form); + + if (cropper && document.getElementById('image').files.length > 0) { + cropper.getCroppedCanvas().toBlob((blob) => { + const fileName = 'cropped_image.png'; + const croppedImage = new File([blob], fileName, { type: 'image/png' }); + formData.append('image', croppedImage); + sendFormData(form.action, formData); + }, 'image/png'); + } else { + sendFormData(form.action, formData); + } +} + +// Outras funções comuns aqui diff --git a/forunb/templates/base.html b/forunb/templates/base.html index 5f4cb78b..2c18ec1e 100644 --- a/forunb/templates/base.html +++ b/forunb/templates/base.html @@ -11,6 +11,7 @@ href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.10.0/font/bootstrap-icons.min.css"> {% load static %} + From e29b03beb4a0aec58e76914f0ec152010ce35354 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Sat, 24 Aug 2024 14:57:23 -0300 Subject: [PATCH 19/51] SonarCloud: updting sonar.exclusions --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index 445a8cb3..ec7d47bf 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -14,4 +14,4 @@ sonar.organization=unb-mds sonar.python.coverage.reportPaths=coverage.xml -sonar.exclusions=**/test_models.py, **/test_views.py, **/asgi.py, **/production.py, **/wsgi.py \ No newline at end of file +sonar.exclusions=**/test_models.py, **/test_views.py, **/asgi.py, **/production.py, **/wsgi.py, **/*.js \ No newline at end of file From 652dd7532ee18c55137d11084992e6a93f6a3047 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Tue, 27 Aug 2024 17:46:00 -0300 Subject: [PATCH 20/51] fix: fixing clean_html view --- forunb/main/views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/forunb/main/views.py b/forunb/main/views.py index 23f7b5bc..dd7047e9 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -96,11 +96,14 @@ def question_detail(request, question_id): def clean_html(text): - """Remove HTML tags from a text.""" - print("Texto recebido pelo clean_html:", text) # Depuração + """Remove HTML tags but preserve line breaks and basic formatting.""" soup = BeautifulSoup(text, 'html.parser') + for br in soup.find_all("br"): + br.replace_with("\n") + for p in soup.find_all("p"): + p.insert(0, "\n") + p.insert(len(p.contents), "\n") cleaned_text = soup.get_text() - print("Texto após limpeza:", cleaned_text) # Depuração return cleaned_text From a64a21b72e3aae56b9c31fb372533fe500845fc3 Mon Sep 17 00:00:00 2001 From: Davi-KLevy Date: Tue, 27 Aug 2024 17:46:44 -0300 Subject: [PATCH 21/51] html: including pre-formatted css style --- forunb/main/templates/main/forum_detail.html | 2 +- forunb/main/templates/main/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/forunb/main/templates/main/forum_detail.html b/forunb/main/templates/main/forum_detail.html index db3b3e1f..47d71b44 100644 --- a/forunb/main/templates/main/forum_detail.html +++ b/forunb/main/templates/main/forum_detail.html @@ -68,7 +68,7 @@

{{ question.title }}
-

{{ question.description }}

+

{{ question.description }}

{% if question.image %} Descrição da imagem relacionada à perguntaÚltimas Perguntas
{{ question.title }}
-

{{ question.description }}

+

{{ question.description }}

{% if question.image %} Descrição da imagem relacionada à pergunta Date: Wed, 28 Aug 2024 15:28:19 -0300 Subject: [PATCH 22/51] feat: adding sobre url --- forunb/main/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/forunb/main/urls.py b/forunb/main/urls.py index 1b9c8cc1..5fa8ff79 100644 --- a/forunb/main/urls.py +++ b/forunb/main/urls.py @@ -21,4 +21,5 @@ path('toggle-upvote-question//', views.toggle_upvote_question, name='toggle_upvote_question'), # pylint: disable=C0301 path('toggle-upvote-answer//', views.toggle_upvote_answer, name='toggle_upvote_answer'), # pylint: disable=C0301 path('report///', views.report, name='report'), + path('sobre/', views.sobre, name='sobre'), ] From e5d5ffbd9b88ce2aa292273b3bba6854873662f8 Mon Sep 17 00:00:00 2001 From: Victor Bernardes Date: Wed, 28 Aug 2024 15:28:45 -0300 Subject: [PATCH 23/51] feat: adding sobre view --- forunb/main/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/forunb/main/views.py b/forunb/main/views.py index 23f7b5bc..6f26a805 100644 --- a/forunb/main/views.py +++ b/forunb/main/views.py @@ -103,7 +103,9 @@ def clean_html(text): print("Texto após limpeza:", cleaned_text) # Depuração return cleaned_text - +def sobre(request): + """Render the sobre page.""" + return render(request, 'main/sobre.html') @login_required(login_url='/users/login') def follow_forum(request, forum_id, action): From ab20ad27463e539000cad6016165a6b4c14860e4 Mon Sep 17 00:00:00 2001 From: Victor Bernardes Date: Wed, 28 Aug 2024 15:29:58 -0300 Subject: [PATCH 24/51] feat: creating sobre button and page --- forunb/main/templates/main/sobre.html | 124 ++++++++++++++++++++++++++ forunb/templates/base.html | 2 + 2 files changed, 126 insertions(+) create mode 100644 forunb/main/templates/main/sobre.html diff --git a/forunb/main/templates/main/sobre.html b/forunb/main/templates/main/sobre.html new file mode 100644 index 00000000..9e471a71 --- /dev/null +++ b/forunb/main/templates/main/sobre.html @@ -0,0 +1,124 @@ +{% extends "base.html" %} + +{% block content %} + + +
+

forUnB

+ +

Sobre

+

+ O forUnB é uma plataforma de fórum inspirada no conceito do Stack Overflow, criada para fomentar a colaboração e + a troca de conhecimento entre alunos e professores da Universidade de + Brasília. + Nosso objetivo é construir uma comunidade unida, onde os estudantes possam compartilhar dúvidas, obter respostas + e + colaborar em diversas disciplinas. +

+

+ Dentro da plataforma, os usuários podem criar perguntas e respostas em fóruns específicos que já + disponibilizamos de toda a FGA, facilitando a comunicação + entre + alunos. Além disso, contamos com um sistema de avaliação que destaca as melhores respostas, + garantindo + que o conteúdo mais útil e relevante seja facilmente acessível a todos. +

+

+ O forUnB não é apenas um espaço para perguntas e respostas, mas também uma ferramenta para promover a + organização + acadêmica e a interação entre diferentes grupos de estudo, tornando o aprendizado uma experiência mais rica e + colaborativa, criando assim uma grande comunidade de estudantes da UnB. +

+ +

Equipe

+ +
+
+
+ Alexandre Junior +
+ Foto Alexandre +
+
+ Bruno Bragança +
+ Foto Bruno +
+
+ Davi Klein +
+ Foto Davi +
+
+
+
+ Manoela Garcia +
+ Foto Manoela +
+
+ Pedro Lopes +
+ Foto Pedro +
+
+ Victor Hugo Bernardes +
+ Foto Victor +
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/forunb/templates/base.html b/forunb/templates/base.html index 2c18ec1e..1fbb4a7f 100644 --- a/forunb/templates/base.html +++ b/forunb/templates/base.html @@ -37,6 +37,8 @@ class="bi bi-star-fill">Meus Fóruns Meus Posts + Sobre + nós