diff --git a/img/line-2.svg b/brainwave/__init__.py similarity index 100% rename from img/line-2.svg rename to brainwave/__init__.py diff --git a/brainwave/__pycache__/__init__.cpython-38.pyc b/brainwave/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..d773277 Binary files /dev/null and b/brainwave/__pycache__/__init__.cpython-38.pyc differ diff --git a/brainwave/__pycache__/settings.cpython-38.pyc b/brainwave/__pycache__/settings.cpython-38.pyc new file mode 100644 index 0000000..b089c41 Binary files /dev/null and b/brainwave/__pycache__/settings.cpython-38.pyc differ diff --git a/brainwave/__pycache__/urls.cpython-38.pyc b/brainwave/__pycache__/urls.cpython-38.pyc new file mode 100644 index 0000000..fc2d581 Binary files /dev/null and b/brainwave/__pycache__/urls.cpython-38.pyc differ diff --git a/brainwave/__pycache__/wsgi.cpython-38.pyc b/brainwave/__pycache__/wsgi.cpython-38.pyc new file mode 100644 index 0000000..d975e06 Binary files /dev/null and b/brainwave/__pycache__/wsgi.cpython-38.pyc differ diff --git a/brainwave/asgi.py b/brainwave/asgi.py new file mode 100644 index 0000000..23af5fe --- /dev/null +++ b/brainwave/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for brainwave project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'brainwave.settings') + +application = get_asgi_application() diff --git a/brainwave/settings.py b/brainwave/settings.py new file mode 100644 index 0000000..8ecb8a1 --- /dev/null +++ b/brainwave/settings.py @@ -0,0 +1,125 @@ +from pathlib import Path +import os + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-_*7_%im@0@58xl)8q^5cibhb6p^bn+788c$-_)lh*-kuf@2k(4' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + +LOGIN_URL = '/login/' +LOGIN_REDIRECT_URL = '/brainwave/' +LOGOUT_REDIRECT_URL = '/brainwave/' + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'core', + 'item', + 'post', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'brainwave.urls' + +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, 'CORE', 'STATIC'), +] + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'brainwave.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = '/static/' +MEDIA_URL = 'media/' +MEDIA_ROOT = BASE_DIR / 'media' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/brainwave/urls.py b/brainwave/urls.py new file mode 100644 index 0000000..a067f86 --- /dev/null +++ b/brainwave/urls.py @@ -0,0 +1,12 @@ +from django.conf import settings +from django.conf.urls.static import static +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('', include('core.urls')), + path('items/', include('item.urls')), + path('post/', include('post.urls')), + path('admin/', admin.site.urls), +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + diff --git a/brainwave/wsgi.py b/brainwave/wsgi.py new file mode 100644 index 0000000..97cd9f1 --- /dev/null +++ b/brainwave/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for brainwave project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'brainwave.settings') + +application = get_wsgi_application() diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/__pycache__/__init__.cpython-38.pyc b/core/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..c3b95f0 Binary files /dev/null and b/core/__pycache__/__init__.cpython-38.pyc differ diff --git a/core/__pycache__/admin.cpython-38.pyc b/core/__pycache__/admin.cpython-38.pyc new file mode 100644 index 0000000..4aac12b Binary files /dev/null and b/core/__pycache__/admin.cpython-38.pyc differ diff --git a/core/__pycache__/apps.cpython-38.pyc b/core/__pycache__/apps.cpython-38.pyc new file mode 100644 index 0000000..f459264 Binary files /dev/null and b/core/__pycache__/apps.cpython-38.pyc differ diff --git a/core/__pycache__/forms.cpython-38.pyc b/core/__pycache__/forms.cpython-38.pyc new file mode 100644 index 0000000..b2d1246 Binary files /dev/null and b/core/__pycache__/forms.cpython-38.pyc differ diff --git a/core/__pycache__/models.cpython-38.pyc b/core/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000..2f8ba6d Binary files /dev/null and b/core/__pycache__/models.cpython-38.pyc differ diff --git a/core/__pycache__/urls.cpython-38.pyc b/core/__pycache__/urls.cpython-38.pyc new file mode 100644 index 0000000..ff61e11 Binary files /dev/null and b/core/__pycache__/urls.cpython-38.pyc differ diff --git a/core/__pycache__/views.cpython-38.pyc b/core/__pycache__/views.cpython-38.pyc new file mode 100644 index 0000000..c13c847 Binary files /dev/null and b/core/__pycache__/views.cpython-38.pyc differ diff --git a/core/admin.py b/core/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/core/apps.py b/core/apps.py new file mode 100644 index 0000000..8115ae6 --- /dev/null +++ b/core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core' diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..29a7245 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,40 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm, AuthenticationForm +from django.contrib.auth.models import User + + +class LoginForm(AuthenticationForm): + username = forms.CharField(widget=forms.TextInput(attrs={ + 'placeholder': 'Nome de Usuário', + 'class': 'w-full py-4 px-6 rounded-xl' + })) + + password = forms.CharField(widget=forms.PasswordInput(attrs={ + 'placeholder': 'Senha', + 'class': 'w-full py-4 px-6 rounded-xl' + })) + +class SignupForm(UserCreationForm): + class Meta: + model = User + fields = ('username', 'email', 'password1', 'password2') + + username = forms.CharField(widget=forms.TextInput(attrs={ + 'placeholder': 'Nome de Usuário', + 'class': 'w-full py-4 px-6 rounded-xl' + })) + + email = forms.CharField(widget=forms.EmailInput(attrs={ + 'placeholder': 'E-mail', + 'class': 'w-full py-4 px-6 rounded-xl' + })) + + password1 = forms.CharField(widget=forms.PasswordInput(attrs={ + 'placeholder': 'Senha', + 'class': 'w-full py-4 px-6 rounded-xl' + })) + + password2 = forms.CharField(widget=forms.PasswordInput(attrs={ + 'placeholder': 'Confirme senha', + 'class': 'w-full py-4 px-6 rounded-xl' + })) \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..d8b2f59 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.7 on 2023-11-27 05:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Thread', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Post', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.thread')), + ], + ), + ] diff --git a/core/migrations/0002_delete_post_delete_thread.py b/core/migrations/0002_delete_post_delete_thread.py new file mode 100644 index 0000000..f43c543 --- /dev/null +++ b/core/migrations/0002_delete_post_delete_thread.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.7 on 2023-11-28 08:30 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.DeleteModel( + name='Post', + ), + migrations.DeleteModel( + name='Thread', + ), + ] diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/migrations/__pycache__/0001_initial.cpython-38.pyc b/core/migrations/__pycache__/0001_initial.cpython-38.pyc new file mode 100644 index 0000000..a69d2ae Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-38.pyc differ diff --git a/core/migrations/__pycache__/0002_delete_post_delete_thread.cpython-38.pyc b/core/migrations/__pycache__/0002_delete_post_delete_thread.cpython-38.pyc new file mode 100644 index 0000000..b13515e Binary files /dev/null and b/core/migrations/__pycache__/0002_delete_post_delete_thread.cpython-38.pyc differ diff --git a/core/migrations/__pycache__/__init__.cpython-38.pyc b/core/migrations/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..16294fb Binary files /dev/null and b/core/migrations/__pycache__/__init__.cpython-38.pyc differ diff --git a/core/models.py b/core/models.py new file mode 100644 index 0000000..b096caa --- /dev/null +++ b/core/models.py @@ -0,0 +1,4 @@ +from django.db import models + +# Create your models here. + diff --git a/css/create_post.css b/core/static/css/create_post.css similarity index 90% rename from css/create_post.css rename to core/static/css/create_post.css index b4056df..35bd808 100644 --- a/css/create_post.css +++ b/core/static/css/create_post.css @@ -17,7 +17,7 @@ padding: 20px 25px; border-radius: 79px; - border: 0px; + border: 2px solid var(--color-black); background-color: var(--color-blueviolet); } @@ -34,7 +34,7 @@ color: white; border-radius: 79px; - border: 0px; + border: 2px solid var(--color-black); background-color: var(--color-blueviolet); } diff --git a/core/static/css/global.css b/core/static/css/global.css new file mode 100644 index 0000000..0fd7250 --- /dev/null +++ b/core/static/css/global.css @@ -0,0 +1,37 @@ +:root { + /* fonts */ + --font-inter: Inter; + --font-inherit: inherit; + --font-arial: Arial; + + /* font sizes */ + --font-size-9xl: 28px; + --font-size-10xl: 29px; + --font-size-13xl: 32px; + --font-size-17xl: 36px; + --font-size-29xl: 48px; + --font-size-45xl: 64px; + + /* Colors */ + --color-gray-200: #1e1e1e; + --color-gray-100: #1f132f; + --color-gray-300: #0d0d0d; + --color-gray-400: #13001e; + --color-white: #fff; + --color-black: #000; + --color-blueviolet: #6b00bf; + --color-fuchsia: #ee00ff; + + /* Gaps */ + --gap-6xl: 25px; + + /* Paddings */ + --padding-18xl: 37px; + --padding-20xl: 39px; + + /* Border radiuses */ + --br-41xl: 60px; + --br-60xl: 79px; + --br-lgi: 19px; + --br-3xs: 10px; + } \ No newline at end of file diff --git a/css/index.css b/core/static/css/index.css similarity index 92% rename from css/index.css rename to core/static/css/index.css index 1c7c808..bf926a8 100644 --- a/css/index.css +++ b/core/static/css/index.css @@ -122,8 +122,6 @@ body { font-size: var(--font-size-13xl); justify-self: center; align-self: center; - - } .login_icon{ @@ -233,3 +231,27 @@ body { appearance: none; background-color: inherit; } + +.dropdown { + text-decoration: none; + color: inherit; +} + +.dropdown-menu{ + width: 150px; + position: absolute; + box-shadow: 0 0 5px #ee00ff; + display: none; + border-radius: 5px; + background-color: #0d0c0c; +} + +.dropdown-menu a{ + display: block; + color: #ee00ff; +} + +.dropdown:hover .dropdown-menu{ + display: block; +} + diff --git a/css/login.css b/core/static/css/login.css similarity index 58% rename from css/login.css rename to core/static/css/login.css index 3c1dc5a..3069b32 100644 --- a/css/login.css +++ b/core/static/css/login.css @@ -1,4 +1,3 @@ - .cadastro{ width: 50%; display:flex; @@ -50,8 +49,48 @@ form button{ color: white; } +.error-container { + background-color: #0d0c0c; + color:#ff0066; + padding: 1rem; + border-radius: 0.25rem; + margin-bottom: 1rem; +} + .login{ width: 50%; display:flex; justify-content: center; -} \ No newline at end of file +} + +/* Estilo para o pop-up */ +.popup { + display: none; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1; +} + +.popup-content { + background-color: #f9f9f9; + padding: 20px; + border: 1px solid #888; + width: 300px; +} + +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + diff --git a/core/static/css/post.css b/core/static/css/post.css new file mode 100644 index 0000000..67df270 --- /dev/null +++ b/core/static/css/post.css @@ -0,0 +1,68 @@ +.novo_post { + display:flex; + align-items: center; + flex-direction: column; + + height: 100%; + + gap: 28px; +} + +.novo_post input{ + font-size: 32px; + color: white; + + width: 577px; + + padding: 20px 25px; + + border-radius: 79px; + border: 0px; + background-color: var(--color-blueviolet); +} + +.novo_post textarea { + resize: none; + + width: 1050px; + height: 200px; + + padding: 20px 50px; + + font-size: 32px; + line-height: 40px; + color: white; + + border-radius: 79px; + border: 2px solid var(--color-black); + background-color: var(--color-blueviolet); +} + + +.novo_post button{ + border: none; + appearance: none; + background-color: inherit; +} + +.post_comment{ + width: 1145px; + height: auto; + padding: 15px 40px; + + border-radius: var(--br-41xl); + background-color: var(--color-blueviolet); + border: 2px solid var(--color-black); + box-sizing: border-box; + color: white; + font-family: var(--font-arial); + font-size: var(--font-size-13xl); +} + +.post_comment .titulo{ + display: flex; + align-items: center; + justify-content: space-between; + gap: 50px; + margin-bottom: 50px; +} \ No newline at end of file diff --git a/core/static/images/bin.png b/core/static/images/bin.png new file mode 100644 index 0000000..d362bf3 Binary files /dev/null and b/core/static/images/bin.png differ diff --git a/img/brain-11@2x.png b/core/static/images/brain-11@2x.png similarity index 100% rename from img/brain-11@2x.png rename to core/static/images/brain-11@2x.png diff --git a/img/brain-1@2x.png b/core/static/images/brain-1@2x.png similarity index 100% rename from img/brain-1@2x.png rename to core/static/images/brain-1@2x.png diff --git a/img/enviar-1@2x.png b/core/static/images/enviar-1@2x.png similarity index 100% rename from img/enviar-1@2x.png rename to core/static/images/enviar-1@2x.png diff --git a/img/home@2x.png b/core/static/images/home@2x.png similarity index 100% rename from img/home@2x.png rename to core/static/images/home@2x.png diff --git a/core/static/images/line-2.svg b/core/static/images/line-2.svg new file mode 100644 index 0000000..e69de29 diff --git a/img/logo@2x.png b/core/static/images/logo@2x.png similarity index 100% rename from img/logo@2x.png rename to core/static/images/logo@2x.png diff --git a/img/mascote@2x.png b/core/static/images/mascote@2x.png similarity index 100% rename from img/mascote@2x.png rename to core/static/images/mascote@2x.png diff --git a/img/onda-roxa@2x.png b/core/static/images/onda-roxa@2x.png similarity index 100% rename from img/onda-roxa@2x.png rename to core/static/images/onda-roxa@2x.png diff --git a/img/pessoa@2x.png b/core/static/images/pessoa@2x.png similarity index 100% rename from img/pessoa@2x.png rename to core/static/images/pessoa@2x.png diff --git a/img/resposta-1-3@2x.png b/core/static/images/resposta-1-3@2x.png similarity index 100% rename from img/resposta-1-3@2x.png rename to core/static/images/resposta-1-3@2x.png diff --git a/img/speechbubble-1-1@2x.png b/core/static/images/speechbubble-1-1@2x.png similarity index 100% rename from img/speechbubble-1-1@2x.png rename to core/static/images/speechbubble-1-1@2x.png diff --git a/core/templates/core/base.html b/core/templates/core/base.html new file mode 100644 index 0000000..e34d119 --- /dev/null +++ b/core/templates/core/base.html @@ -0,0 +1,56 @@ + + + + + + + + + + {% block title %}{% endblock %} | Puddle + + + + + +
+ {% block content %} + {% endblock %} +
+ + + + \ No newline at end of file diff --git a/core/templates/core/brainwave.html b/core/templates/core/brainwave.html new file mode 100644 index 0000000..ec9bffb --- /dev/null +++ b/core/templates/core/brainwave.html @@ -0,0 +1,119 @@ +{% load static %} + + + + + + + + + + + + {% block title %}Página Inicial | Brainwave{% endblock %} + + + +
+
+ + + + “Conectando mentes acadêmicas” - GRAN +
Brainwave
+
Network
+ + +
+
+ + +
Início
+
+
+
+ +
+
+ {% if request.user.is_authenticated %} + + {% else %} + Cadastro + Login + {% endif %} +
+ + + + +
+
+
+ +
+
+

Em Alta

+
    + {% for post in posts_by_likes %} + +
  1. {{ post.titulo }}
  2. +
    + {% endfor %} +
+
+ +
+ {% for post in posts_by_date %} +
+
+

{{ post.created_by.username }}

+ +

{{ post.titulo }}

+
+
+

{{ post.texto }}

+
+
+ +

{{ post.likes.count }}

+ +
+ + + +
+
+ {% endfor %} +
+ +
+
+ + + + diff --git a/core/templates/core/index.html b/core/templates/core/index.html new file mode 100644 index 0000000..51c7cfe --- /dev/null +++ b/core/templates/core/index.html @@ -0,0 +1,43 @@ +{% extends 'core/base.html' %} + +{% block title %}Welcome{% endblock %} + +{% block content %} +
+

Newest items

+ +
+ {% for item in items %} +
+ +
+ +
+ +
+

{{ item.name }}

+

Price: {{ item.price }}

+
+
+
+ {% endfor %} +
+
+ +
+

Categories

+ +
+ {% for category in categories %} +
+ +
+

{{ item.name }}

+

{{ category.items.count }} items

+
+
+
+ {% endfor %} +
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/login.html b/core/templates/core/login.html new file mode 100644 index 0000000..e422f05 --- /dev/null +++ b/core/templates/core/login.html @@ -0,0 +1,91 @@ +{% load static %} + + + + + + + + + + + + {% block title %}Login | Brainwave{% endblock %} + + + + +
+
+ + + + “Conectando mentes acadêmicas” - GRAN +
Brainwave
+
Network
+ +
+
+ + +
Início
+
+
+
+ +
+
+ {% if request.user.is_authenticated %} + + {% else %} + Cadastro + Login + {% endif %} +
+ + + + +
+
+
+ + +
+
+ +
+
+ +
+ + diff --git a/core/templates/core/register.html b/core/templates/core/register.html new file mode 100644 index 0000000..dfdad8a --- /dev/null +++ b/core/templates/core/register.html @@ -0,0 +1,93 @@ +{% load static %} + + + + + + + + + + + + {% block title %}Cadastro | Brainwave{% endblock %} + + + + +
+
+ + + + “Conectando mentes acadêmicas” - GRAN +
Brainwave
+
Network
+ +
+
+ + +
Início
+
+
+
+ +
+
+ {% if request.user.is_authenticated %} + + {% else %} + Cadastro + Login + {% endif %} +
+ + + + +
+
+
+ + + +
+
+
+
+ {% csrf_token %} + +

Cadastro

+ {{ form.email }} + + {{ form.username }} + + {{ form.password1 }} + + {{ form.password2 }} + + {% if form.errors or form.non_field_errors %} +
+ {% for field in form %} + {{ field.errors }} + {% endfor %} + + {{ form.non_field_errors }} + +
+ {% endif %} + + +
+
+
+
+
+ + diff --git a/core/tests.py b/core/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/core/urls.py b/core/urls.py new file mode 100644 index 0000000..1b2be10 --- /dev/null +++ b/core/urls.py @@ -0,0 +1,18 @@ +from django.contrib.auth import views as auth_views +from django.urls import path + +from . import views +from .views import logout_view, delete_account +from .forms import LoginForm + +app_name = 'core' + +urlpatterns = [ + path('', views.index, name='index'), + + path('register/', views.signup, name='register'), + path('login/', auth_views.LoginView.as_view(template_name='core/login.html', authentication_form=LoginForm), name='login'), + path('logout/', logout_view, name='logout'), + path('delete/', delete_account, name='delete'), + path('brainwave/', views.brainwave, name='brainwave'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py new file mode 100644 index 0000000..79055c1 --- /dev/null +++ b/core/views.py @@ -0,0 +1,55 @@ +from django.shortcuts import render, redirect +from django.contrib.auth.decorators import login_required +from django.contrib.auth import logout, authenticate, login +from django.contrib.auth.forms import AuthenticationForm +from item.models import Category, Item +from django.db.models import Count +from post.models import Post +from .forms import SignupForm, LoginForm + +def contact(request): + return render(request, 'core/contact.html') + +def brainwave(request): + # Obtenha os posts ordenados pela contagem de curtidas (do maior para o menor) + posts_by_likes = Post.objects.annotate(likes_count=Count('likes')).order_by('-likes_count') + + # Obtenha os posts ordenados pela data de criação (do mais recente para o mais antigo) + posts_by_date = Post.objects.all().order_by('-created_at') + + # Renderize o template 'brainwave.html' com as duas listas de posts + return render(request, 'core/brainwave.html', {'posts_by_likes': posts_by_likes, 'posts_by_date': posts_by_date}) + +def index(request): + # Obtenha os posts ordenados pela contagem de curtidas (do maior para o menor) + posts_by_likes = Post.objects.annotate(likes_count=Count('likes')).order_by('-likes_count') + + # Obtenha os posts ordenados pela data de criação (do mais recente para o mais antigo) + posts_by_date = Post.objects.all().order_by('-created_at') + + # Renderize o template 'brainwave.html' com as duas listas de posts + return render(request, 'core/brainwave.html', {'posts_by_likes': posts_by_likes, 'posts_by_date': posts_by_date}) + +def signup(request): + if request.method == 'POST': + form = SignupForm(request.POST) + + if form.is_valid(): + form.save() + return redirect('core:login') + + else: + form = SignupForm() + + return render(request, 'core/register.html', {'form': form}) + +def logout_view(request): + logout(request) + return redirect('core:brainwave') + +@login_required +def delete_account(request): + # Excluir o usuário e desconectar + request.user.delete() + logout(request) + return redirect('core:brainwave') \ No newline at end of file diff --git a/css/global.css b/css/global.css deleted file mode 100644 index d1b1ea2..0000000 --- a/css/global.css +++ /dev/null @@ -1,39 +0,0 @@ - - -:root { - /* fonts */ - --font-inter: Inter; - --font-inherit: inherit; - --font-arial: Arial; - - /* font sizes */ - --font-size-9xl: 28px; - --font-size-10xl: 29px; - --font-size-13xl: 32px; - --font-size-17xl: 36px; - --font-size-29xl: 48px; - --font-size-45xl: 64px; - - /* Colors */ - --color-gray-200: #1e1e1e; - --color-gray-100: #1f132f; - --color-gray-300: #0d0d0d; - --color-gray-400: #13001e; - --color-white: #fff; - --color-black: #000; - --color-blueviolet: #6b00bf; - --color-fuchsia: #ee00ff; - - /* Gaps */ - --gap-6xl: 25px; - - /* Paddings */ - --padding-18xl: 37px; - --padding-20xl: 39px; - - /* Border radiuses */ - --br-41xl: 60px; - --br-60xl: 79px; - --br-lgi: 19px; - --br-3xs: 10px; -} diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000..87b049f Binary files /dev/null and b/db.sqlite3 differ diff --git a/index.html b/index.html deleted file mode 100644 index 49b9cac..0000000 --- a/index.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - -
-
- - - - “Conectando mentes acadêmicas” - GRAN -
Brainwave
-
Network
- -
-
- - -
Início
-
-
+
- -
-
- -
-
-

EM ALTA

- -
- -
-
-
-

USUÁRIO

-

TÍTULO

-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-
-

5

- - - - -
-
- -
-
-

USUÁRIO

-

TÍTULO

-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.

-
-

3

- - - - -
-
- -
-
-

USUÁRIO

-

TÍTULO

-
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-
-

1

- - - - -
-
-
- -
- -
- - - - diff --git a/item/__init__.py b/item/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/item/__pycache__/__init__.cpython-38.pyc b/item/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..53f7689 Binary files /dev/null and b/item/__pycache__/__init__.cpython-38.pyc differ diff --git a/item/__pycache__/admin.cpython-38.pyc b/item/__pycache__/admin.cpython-38.pyc new file mode 100644 index 0000000..4182bf6 Binary files /dev/null and b/item/__pycache__/admin.cpython-38.pyc differ diff --git a/item/__pycache__/apps.cpython-38.pyc b/item/__pycache__/apps.cpython-38.pyc new file mode 100644 index 0000000..1e49298 Binary files /dev/null and b/item/__pycache__/apps.cpython-38.pyc differ diff --git a/item/__pycache__/forms.cpython-38.pyc b/item/__pycache__/forms.cpython-38.pyc new file mode 100644 index 0000000..457b426 Binary files /dev/null and b/item/__pycache__/forms.cpython-38.pyc differ diff --git a/item/__pycache__/models.cpython-38.pyc b/item/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000..9048f0a Binary files /dev/null and b/item/__pycache__/models.cpython-38.pyc differ diff --git a/item/__pycache__/urls.cpython-38.pyc b/item/__pycache__/urls.cpython-38.pyc new file mode 100644 index 0000000..c5c1715 Binary files /dev/null and b/item/__pycache__/urls.cpython-38.pyc differ diff --git a/item/__pycache__/views.cpython-38.pyc b/item/__pycache__/views.cpython-38.pyc new file mode 100644 index 0000000..8522ede Binary files /dev/null and b/item/__pycache__/views.cpython-38.pyc differ diff --git a/item/admin.py b/item/admin.py new file mode 100644 index 0000000..28ff820 --- /dev/null +++ b/item/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +#TUDO FAZ REFERENCIA A TELA DE ADMIN DO SITE + +from .models import Category, Item + +admin.site.register(Category) +admin.site.register(Item) \ No newline at end of file diff --git a/item/apps.py b/item/apps.py new file mode 100644 index 0000000..bed08f9 --- /dev/null +++ b/item/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + +class ItemConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'item' diff --git a/item/forms.py b/item/forms.py new file mode 100644 index 0000000..7e2b1f7 --- /dev/null +++ b/item/forms.py @@ -0,0 +1,46 @@ +from django import forms + +from .models import Item + +INPUT_CLASSES = 'w-full py-4 px-6 rounded-xl border' + +class NewItemForm(forms.ModelForm): + class Meta: + model = Item + fields = ('category', 'name', 'description', 'price', 'image',) + widgets = { + 'category': forms.Select(attrs={ + 'class': INPUT_CLASSES + }), + 'name': forms.TextInput(attrs={ + 'class': INPUT_CLASSES + }), + 'description': forms.Textarea(attrs={ + 'class': INPUT_CLASSES + }), + 'price': forms.TextInput(attrs={ + 'class': INPUT_CLASSES + }), + 'image': forms.FileInput(attrs={ + 'class': INPUT_CLASSES + }) + } + +class EditItemForm(forms.ModelForm): + class Meta: + model = Item + fields = ('name', 'description', 'price', 'image', 'is_sold') + widgets = { + 'name': forms.TextInput(attrs={ + 'class': INPUT_CLASSES + }), + 'description': forms.Textarea(attrs={ + 'class': INPUT_CLASSES + }), + 'price': forms.TextInput(attrs={ + 'class': INPUT_CLASSES + }), + 'image': forms.FileInput(attrs={ + 'class': INPUT_CLASSES + }) + } \ No newline at end of file diff --git a/item/migrations/0001_initial.py b/item/migrations/0001_initial.py new file mode 100644 index 0000000..63d5b89 --- /dev/null +++ b/item/migrations/0001_initial.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.7 on 2023-11-26 04:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ], + ), + ] diff --git a/item/migrations/0002_alter_category_options_item.py b/item/migrations/0002_alter_category_options_item.py new file mode 100644 index 0000000..0fefa83 --- /dev/null +++ b/item/migrations/0002_alter_category_options_item.py @@ -0,0 +1,34 @@ +# Generated by Django 4.2.7 on 2023-11-26 04:56 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('item', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='category', + options={'ordering': ('name',), 'verbose_name_plural': 'Categories'}, + ), + migrations.CreateModel( + name='Item', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True, null=True)), + ('price', models.FloatField()), + ('image', models.ImageField(blank=True, null=True, upload_to='items_images')), + ('is_sold', models.BooleanField(default=False)), + ('create_at', models.DateTimeField(auto_now_add=True)), + ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='item.category')), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/item/migrations/0003_rename_create_at_item_created_at_alter_item_image.py b/item/migrations/0003_rename_create_at_item_created_at_alter_item_image.py new file mode 100644 index 0000000..92ed121 --- /dev/null +++ b/item/migrations/0003_rename_create_at_item_created_at_alter_item_image.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2023-11-27 07:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('item', '0002_alter_category_options_item'), + ] + + operations = [ + migrations.RenameField( + model_name='item', + old_name='create_at', + new_name='created_at', + ), + migrations.AlterField( + model_name='item', + name='image', + field=models.ImageField(blank=True, null=True, upload_to='item_images'), + ), + ] diff --git a/item/migrations/__init__.py b/item/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/item/migrations/__pycache__/0001_initial.cpython-38.pyc b/item/migrations/__pycache__/0001_initial.cpython-38.pyc new file mode 100644 index 0000000..729ab98 Binary files /dev/null and b/item/migrations/__pycache__/0001_initial.cpython-38.pyc differ diff --git a/item/migrations/__pycache__/0002_alter_category_options_item.cpython-38.pyc b/item/migrations/__pycache__/0002_alter_category_options_item.cpython-38.pyc new file mode 100644 index 0000000..d101ca2 Binary files /dev/null and b/item/migrations/__pycache__/0002_alter_category_options_item.cpython-38.pyc differ diff --git a/item/migrations/__pycache__/0003_rename_create_at_item_created_at_alter_item_image.cpython-38.pyc b/item/migrations/__pycache__/0003_rename_create_at_item_created_at_alter_item_image.cpython-38.pyc new file mode 100644 index 0000000..11f501a Binary files /dev/null and b/item/migrations/__pycache__/0003_rename_create_at_item_created_at_alter_item_image.cpython-38.pyc differ diff --git a/item/migrations/__pycache__/__init__.cpython-38.pyc b/item/migrations/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..e14e568 Binary files /dev/null and b/item/migrations/__pycache__/__init__.cpython-38.pyc differ diff --git a/item/models.py b/item/models.py new file mode 100644 index 0000000..2cb7afc --- /dev/null +++ b/item/models.py @@ -0,0 +1,25 @@ +from django.contrib.auth.models import User +from django.db import models + +class Category(models.Model): + name = models.CharField(max_length=255) + + class Meta: + ordering = ('name',) + verbose_name_plural = 'Categories' + + def __str__(self): + return self.name + +class Item(models.Model): + category = models.ForeignKey(Category, related_name='items', on_delete=models.CASCADE) + name = models.CharField(max_length=255) + description = models.TextField(blank=True, null=True) + price = models.FloatField() + image = models.ImageField(upload_to='item_images', blank=True, null=True) + is_sold = models.BooleanField(default=False) + created_by = models.ForeignKey(User, related_name='items', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name \ No newline at end of file diff --git a/item/templates/item/detail.html b/item/templates/item/detail.html new file mode 100644 index 0000000..afef7f0 --- /dev/null +++ b/item/templates/item/detail.html @@ -0,0 +1,56 @@ +{% extends 'core/base.html' %} + +{% block title %}{{ item.name }}{% endblock %} + +{% block content %} +
+
+ +
+ +
+

{{ item.name }}

+

Price: {{ item.price }}

+

Seller: {{ item.created_by.username }}

+ + {% if item.description %} +

+ Description:
+ {{ item.description }} +

+ {% endif %} + + {% if request.user == item.created_by %} +
+

This is your item!

+ + Edit + Delete +
+ {% else %} + Contact seller + {% endif %} +
+
+ +
+

Related items

+ +
+ {% for item in related_items %} +
+ +
+ +
+ +
+

{{ item.name }}

+

Price: {{ item.price }}

+
+
+
+ {% endfor %} +
+
+{% endblock %} \ No newline at end of file diff --git a/item/templates/item/form.html b/item/templates/item/form.html new file mode 100644 index 0000000..f2d988b --- /dev/null +++ b/item/templates/item/form.html @@ -0,0 +1,27 @@ +{% extends 'core/base.html' %} + +{% block title %}{{ title }}{% endblock %} + +{% block content %} +

{{ title }}

+ +
+ {% csrf_token %} + +
+ {{ form.as_p }} +
+ + {% if form.errors or form.non_field_errors %} +
+ {% for field in form %} + {{ field.errors }} + {% endfor %} + + {{ form.non_field_errors }} +
+ {% endif %} + + +
+{% endblock %} \ No newline at end of file diff --git a/item/templates/item/items.html b/item/templates/item/items.html new file mode 100644 index 0000000..87344d3 --- /dev/null +++ b/item/templates/item/items.html @@ -0,0 +1,53 @@ +{% extends 'core/base.html' %} + +{% block title %}Items{% endblock %} + +{% block content %} +
+
+
+ + + +
+ +
+ +

Categories

+ + + +
+ +

Clear filters

+ +
+ +
+
+ {% for item in items %} +
+ +
+ +
+ +
+

{{ item.name }}

+

Price: {{ item.price }}

+
+
+
+ {% endfor %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/item/tests.py b/item/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/item/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/item/urls.py b/item/urls.py new file mode 100644 index 0000000..7f77ef7 --- /dev/null +++ b/item/urls.py @@ -0,0 +1,13 @@ +from django.urls import path + +from . import views + +app_name = 'item' + +urlpatterns = [ + path('', views.items, name='items'), + path('new/', views.new, name='new'), + path('/', views.detail, name='detail'), + path('/delete/', views.delete, name='delete'), + path('/edit/', views.edit, name='edit'), +] \ No newline at end of file diff --git a/item/views.py b/item/views.py new file mode 100644 index 0000000..6eb1ae1 --- /dev/null +++ b/item/views.py @@ -0,0 +1,81 @@ +from django.contrib.auth.decorators import login_required +from django.db.models import Q +from django.shortcuts import render, get_object_or_404, redirect + +from .forms import NewItemForm, EditItemForm +from .models import Category, Item + +def items(request): + query = request.GET.get('query', '') + category_id = request.GET.get('category', 0) + categories = Category.objects.all() + items = Item.objects.filter(is_sold=False) + + if category_id: + items = items.filter(category_id=category_id) + + if query: + items = items.filter(Q(name__icontains=query) | Q(description__icontains=query)) + + items = items.order_by('-price') + + return render(request, 'item/items.html', { + 'items': items, + 'query': query, + 'categories': categories, + 'category_id': int(category_id) + }) + +def detail(request, pk): + item = get_object_or_404(Item, pk=pk) + related_items = Item.objects.filter(category=item.category, is_sold=False).exclude(pk=pk)[0:3] + + return render(request, 'item/detail.html', { + 'item': item, + 'related_items': related_items + }) + +@login_required +def new(request): + if request.method == 'POST': + form = NewItemForm(request.POST, request.FILES) + + if form.is_valid(): + item = form.save(commit=False) + item.created_by = request.user + item.save() + + return redirect('item:detail', pk=item.id) + else: + form = NewItemForm() + + return render(request, 'item/form.html', { + 'form': form, + 'title': 'New item', + }) + +@login_required +def edit(request, pk): + item = get_object_or_404(Item, pk=pk, created_by=request.user) + + if request.method == 'POST': + form = EditItemForm(request.POST, request.FILES, instance=item) + + if form.is_valid(): + form.save() + + return redirect('item:detail', pk=item.id) + else: + form = EditItemForm(instance=item) + + return render(request, 'item/form.html', { + 'form': form, + 'title': 'Edit item', + }) + +@login_required +def delete(request, pk): + item = get_object_or_404(Item, pk=pk, created_by=request.user) + item.delete() + + return redirect('dashboard:index') \ No newline at end of file diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..44c2620 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'brainwave.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/media/item_images/068fff422032b9bc512f69ea4fcdc4b5.jpg b/media/item_images/068fff422032b9bc512f69ea4fcdc4b5.jpg new file mode 100644 index 0000000..c05a2dd Binary files /dev/null and b/media/item_images/068fff422032b9bc512f69ea4fcdc4b5.jpg differ diff --git a/media/item_images/22e62412b0d7e675d760eb5c436574c5.png b/media/item_images/22e62412b0d7e675d760eb5c436574c5.png new file mode 100644 index 0000000..def232a Binary files /dev/null and b/media/item_images/22e62412b0d7e675d760eb5c436574c5.png differ diff --git a/media/item_images/5c0afb574f45593454b3a16634235716.jpg b/media/item_images/5c0afb574f45593454b3a16634235716.jpg new file mode 100644 index 0000000..b16d844 Binary files /dev/null and b/media/item_images/5c0afb574f45593454b3a16634235716.jpg differ diff --git a/media/item_images/5c0afb574f45593454b3a16634235716_guDBwKc.jpg b/media/item_images/5c0afb574f45593454b3a16634235716_guDBwKc.jpg new file mode 100644 index 0000000..b16d844 Binary files /dev/null and b/media/item_images/5c0afb574f45593454b3a16634235716_guDBwKc.jpg differ diff --git a/media/items_images/6abfbbb052f77a936a5b0af80c118543.jpg b/media/items_images/6abfbbb052f77a936a5b0af80c118543.jpg new file mode 100644 index 0000000..5041f86 Binary files /dev/null and b/media/items_images/6abfbbb052f77a936a5b0af80c118543.jpg differ diff --git a/media/items_images/download.jpg b/media/items_images/download.jpg new file mode 100644 index 0000000..3d47d5d Binary files /dev/null and b/media/items_images/download.jpg differ diff --git a/pgs/create_post.html b/pgs/create_post.html deleted file mode 100644 index b4a1dff..0000000 --- a/pgs/create_post.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - -
-
- - - - “Conectando mentes acadêmicas” - GRAN -
Brainwave
-
Network
-
-
- - - -
-
+
- -
-
- -
-
-

EM ALTA

- -
-
-
- - - -
-
-
- -
- - \ No newline at end of file diff --git a/pgs/login.html b/pgs/login.html deleted file mode 100644 index 3a363d9..0000000 --- a/pgs/login.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - -
-
- - - - “Conectando mentes acadêmicas” - GRAN -
Brainwave
-
Network
-
-
- - - -
-
+
- -
-
- -
-
-
-
-

Cadastro

- - - - - - - - - -
-
- -
-
- -
- - \ No newline at end of file diff --git a/post/__init__.py b/post/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/post/__pycache__/__init__.cpython-38.pyc b/post/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..29e0b59 Binary files /dev/null and b/post/__pycache__/__init__.cpython-38.pyc differ diff --git a/post/__pycache__/admin.cpython-38.pyc b/post/__pycache__/admin.cpython-38.pyc new file mode 100644 index 0000000..39829e9 Binary files /dev/null and b/post/__pycache__/admin.cpython-38.pyc differ diff --git a/post/__pycache__/apps.cpython-38.pyc b/post/__pycache__/apps.cpython-38.pyc new file mode 100644 index 0000000..4974b51 Binary files /dev/null and b/post/__pycache__/apps.cpython-38.pyc differ diff --git a/post/__pycache__/forms.cpython-38.pyc b/post/__pycache__/forms.cpython-38.pyc new file mode 100644 index 0000000..97bfa78 Binary files /dev/null and b/post/__pycache__/forms.cpython-38.pyc differ diff --git a/post/__pycache__/models.cpython-38.pyc b/post/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000..3e3b660 Binary files /dev/null and b/post/__pycache__/models.cpython-38.pyc differ diff --git a/post/__pycache__/urls.cpython-38.pyc b/post/__pycache__/urls.cpython-38.pyc new file mode 100644 index 0000000..6d1ad95 Binary files /dev/null and b/post/__pycache__/urls.cpython-38.pyc differ diff --git a/post/__pycache__/views.cpython-38.pyc b/post/__pycache__/views.cpython-38.pyc new file mode 100644 index 0000000..17cdd6c Binary files /dev/null and b/post/__pycache__/views.cpython-38.pyc differ diff --git a/post/admin.py b/post/admin.py new file mode 100644 index 0000000..a58fa43 --- /dev/null +++ b/post/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + + +from .models import Category, Post + +admin.site.register(Category) +admin.site.register(Post) \ No newline at end of file diff --git a/post/apps.py b/post/apps.py new file mode 100644 index 0000000..69463e6 --- /dev/null +++ b/post/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PostConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'post' diff --git a/post/forms.py b/post/forms.py new file mode 100644 index 0000000..9b67790 --- /dev/null +++ b/post/forms.py @@ -0,0 +1,44 @@ +from django import forms + +from .models import Post, Comment + +INPUT_CLASSES = 'w-full py-4 px-6 rounded-xl border' + +class NewPostForm(forms.ModelForm): + class Meta: + model = Post + fields = ('titulo', 'texto') + widgets = { + 'titulo': forms.TextInput(attrs={ + 'placeholder': 'Título', + 'class': INPUT_CLASSES + }), + 'texto': forms.Textarea(attrs={ + 'placeholder': 'Escreva sua publicação', + 'class': INPUT_CLASSES + }), + } + +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = ['texto'] + widgets = { + 'texto': forms.Textarea(attrs={ + 'placeholder': 'Escreva seu comentário', + 'class': INPUT_CLASSES + }), + } + +class EditPostForm(forms.ModelForm): + class Meta: + model = Post + fields = ('titulo', 'texto') + widgets = { + 'titulo': forms.TextInput(attrs={ + 'class': INPUT_CLASSES + }), + 'texto': forms.Textarea(attrs={ + 'class': INPUT_CLASSES + }) + } \ No newline at end of file diff --git a/post/migrations/0001_initial.py b/post/migrations/0001_initial.py new file mode 100644 index 0000000..c6f0e14 --- /dev/null +++ b/post/migrations/0001_initial.py @@ -0,0 +1,39 @@ +# Generated by Django 4.2.7 on 2023-11-27 19:31 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ], + options={ + 'verbose_name_plural': 'Categories', + 'ordering': ('name',), + }, + ), + migrations.CreateModel( + name='Post', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts', to='post.category')), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/post/migrations/0002_remove_post_category_remove_post_description_and_more.py b/post/migrations/0002_remove_post_category_remove_post_description_and_more.py new file mode 100644 index 0000000..705a526 --- /dev/null +++ b/post/migrations/0002_remove_post_category_remove_post_description_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.7 on 2023-11-28 02:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('post', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='post', + name='category', + ), + migrations.RemoveField( + model_name='post', + name='description', + ), + migrations.RemoveField( + model_name='post', + name='name', + ), + migrations.AddField( + model_name='post', + name='texto', + field=models.TextField(default='Seu valor padrão aqui', max_length=255), + ), + migrations.AddField( + model_name='post', + name='titulo', + field=models.CharField(default='Seu valor padrao', max_length=50), + preserve_default=False, + ), + ] diff --git a/post/migrations/0003_comment.py b/post/migrations/0003_comment.py new file mode 100644 index 0000000..fe2acc9 --- /dev/null +++ b/post/migrations/0003_comment.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2023-11-28 03:33 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('post', '0002_remove_post_category_remove_post_description_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('texto', models.TextField()), + ('data_criacao', models.DateTimeField(auto_now_add=True)), + ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='post.post')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/post/migrations/0004_comment_likes_post_likes_alter_post_texto.py b/post/migrations/0004_comment_likes_post_likes_alter_post_texto.py new file mode 100644 index 0000000..397350e --- /dev/null +++ b/post/migrations/0004_comment_likes_post_likes_alter_post_texto.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.7 on 2023-11-28 05:13 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('post', '0003_comment'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='likes', + field=models.ManyToManyField(blank=True, related_name='comment_likes', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='post', + name='likes', + field=models.ManyToManyField(blank=True, related_name='post_likes', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='post', + name='texto', + field=models.TextField(default='', max_length=255), + ), + ] diff --git a/post/migrations/0005_alter_comment_likes_alter_post_likes.py b/post/migrations/0005_alter_comment_likes_alter_post_likes.py new file mode 100644 index 0000000..d75fdb8 --- /dev/null +++ b/post/migrations/0005_alter_comment_likes_alter_post_likes.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2023-11-28 06:10 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('post', '0004_comment_likes_post_likes_alter_post_texto'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='likes', + field=models.ManyToManyField(related_name='comment_likes', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='post', + name='likes', + field=models.ManyToManyField(related_name='post_likes', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/post/migrations/0006_alter_comment_likes_alter_post_likes.py b/post/migrations/0006_alter_comment_likes_alter_post_likes.py new file mode 100644 index 0000000..ae8a35c --- /dev/null +++ b/post/migrations/0006_alter_comment_likes_alter_post_likes.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2023-11-28 08:30 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('post', '0005_alter_comment_likes_alter_post_likes'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='likes', + field=models.ManyToManyField(blank=True, related_name='comment_likes', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='post', + name='likes', + field=models.ManyToManyField(blank=True, related_name='post_likes', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/post/migrations/__init__.py b/post/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/post/migrations/__pycache__/0001_initial.cpython-38.pyc b/post/migrations/__pycache__/0001_initial.cpython-38.pyc new file mode 100644 index 0000000..69961f0 Binary files /dev/null and b/post/migrations/__pycache__/0001_initial.cpython-38.pyc differ diff --git a/post/migrations/__pycache__/0002_remove_post_category_remove_post_description_and_more.cpython-38.pyc b/post/migrations/__pycache__/0002_remove_post_category_remove_post_description_and_more.cpython-38.pyc new file mode 100644 index 0000000..a5c2974 Binary files /dev/null and b/post/migrations/__pycache__/0002_remove_post_category_remove_post_description_and_more.cpython-38.pyc differ diff --git a/post/migrations/__pycache__/0003_comment.cpython-38.pyc b/post/migrations/__pycache__/0003_comment.cpython-38.pyc new file mode 100644 index 0000000..a109750 Binary files /dev/null and b/post/migrations/__pycache__/0003_comment.cpython-38.pyc differ diff --git a/post/migrations/__pycache__/0004_comment_likes_post_likes_alter_post_texto.cpython-38.pyc b/post/migrations/__pycache__/0004_comment_likes_post_likes_alter_post_texto.cpython-38.pyc new file mode 100644 index 0000000..75d45f7 Binary files /dev/null and b/post/migrations/__pycache__/0004_comment_likes_post_likes_alter_post_texto.cpython-38.pyc differ diff --git a/post/migrations/__pycache__/0005_alter_comment_likes_alter_post_likes.cpython-38.pyc b/post/migrations/__pycache__/0005_alter_comment_likes_alter_post_likes.cpython-38.pyc new file mode 100644 index 0000000..2af65ad Binary files /dev/null and b/post/migrations/__pycache__/0005_alter_comment_likes_alter_post_likes.cpython-38.pyc differ diff --git a/post/migrations/__pycache__/0006_alter_comment_likes_alter_post_likes.cpython-38.pyc b/post/migrations/__pycache__/0006_alter_comment_likes_alter_post_likes.cpython-38.pyc new file mode 100644 index 0000000..7908bff Binary files /dev/null and b/post/migrations/__pycache__/0006_alter_comment_likes_alter_post_likes.cpython-38.pyc differ diff --git a/post/migrations/__pycache__/__init__.cpython-38.pyc b/post/migrations/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..4517c8f Binary files /dev/null and b/post/migrations/__pycache__/__init__.cpython-38.pyc differ diff --git a/post/models.py b/post/models.py new file mode 100644 index 0000000..e4cbc0d --- /dev/null +++ b/post/models.py @@ -0,0 +1,29 @@ +from django.contrib.auth.models import User +from django.db import models + +class Category(models.Model): + name = models.CharField(max_length=255) + + class Meta: + ordering = ('name',) + verbose_name_plural = 'Categories' + + def __str__(self): + return self.name + +class Post(models.Model): + titulo = models.CharField(max_length=50) + texto = models.TextField(max_length=255, default='') + created_by = models.ForeignKey(User, related_name='posts', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + likes = models.ManyToManyField(User, related_name='post_likes', blank=True) + + def __str__(self): + return self.titulo + +class Comment(models.Model): + post = models.ForeignKey(Post, on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE) + texto = models.TextField() + data_criacao = models.DateTimeField(auto_now_add=True) + likes = models.ManyToManyField(User, related_name='comment_likes', blank=True) diff --git a/post/templates/create_post.html b/post/templates/create_post.html new file mode 100644 index 0000000..82388c4 --- /dev/null +++ b/post/templates/create_post.html @@ -0,0 +1,84 @@ +{% load static %} + + + + + + {% static 'css/index.css' %} + + + + + {% block title %}Criar Post | Brainwave{% endblock %} + + + +
+
+ + + + “Conectando mentes acadêmicas” - GRAN +
Brainwave
+
Network
+ + +
+
+ + + +
+
+
+ +
+
+ {% if request.user.is_authenticated %} + + {% else %} + Cadastro + Login + {% endif %} +
+ + + + +
+
+
+ +
+
+
+ {% csrf_token %} + + {{ form.titulo }} + + {{ form.texto }} + + {% if form.errors or form.non_field_errors %} +
+ {% for field in form %} + {{ field.errors }} + {% endfor %} + + {{ form.non_field_errors }} +
+ {% endif %} + + +
+
+
+
+ + \ No newline at end of file diff --git a/post/templates/post.html b/post/templates/post.html new file mode 100644 index 0000000..01eaeb6 --- /dev/null +++ b/post/templates/post.html @@ -0,0 +1,168 @@ +{% load static %} + + + + + + + + + + + + {% block title %}Post | Brainwave{% endblock %} + + + +
+
+ + + + “Conectando mentes acadêmicas” - GRAN +
Brainwave
+
Network
+
+
+ + +
+
+
+
+
+ {% if request.user.is_authenticated %} + + {% else %} + Cadastro + Login + {% endif %} +
+ + + + +
+
+ + +
+ + + +
+
+
+

{{ post.created_by.username }}

+

{{ post.titulo }}

+ {% if post.created_by == request.user %} +
+ {% csrf_token %} + +
+ {% endif %} +
+ + + +

{{ post.texto }}

+ +
+

{{ post.likes.count }}

+ +
+
+ + +
+ {% csrf_token %} + {{ comment_form.texto }} + +
+ + {% for comment in comments %} +
+
+

{{ comment.user.username }}

+ {% if comment.user == request.user %} +
+ {% csrf_token %} + +
+ {% endif %} + +
+

{{ comment.texto }}

+
+

{{ comment.likes.count }}

+ +
+
+ {% endfor %} +
+
+ + + + + + + diff --git a/post/tests.py b/post/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/post/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/post/urls.py b/post/urls.py new file mode 100644 index 0000000..90867d8 --- /dev/null +++ b/post/urls.py @@ -0,0 +1,18 @@ +from django.urls import path + +from . import views +from .views import post_detail + +app_name = 'post' + +urlpatterns = [ + path('', views.posts, name='posts'), + path('new/', views.new, name='new'), + path('/', views.detail, name='detail'), + path('/delete/', views.delete, name='delete'), + path('/', post_detail, name='post_detail'), + path('/edit/', views.edit, name='edit'), + path('/like/', views.like_post, name='like_post'), + path('comment//like/', views.like_comment, name='like_comment'), + path('comment//delete/', views.delete_comment, name='delete_comment'), +] \ No newline at end of file diff --git a/post/views.py b/post/views.py new file mode 100644 index 0000000..46bb704 --- /dev/null +++ b/post/views.py @@ -0,0 +1,163 @@ +from django.contrib.auth.decorators import login_required +from django.db.models import Q +from django.shortcuts import render, get_object_or_404, redirect +from django.http import JsonResponse +from django.contrib import messages +from django.core.exceptions import PermissionDenied +from .forms import NewPostForm, EditPostForm, CommentForm +from .models import Category, Post, Comment + + +def posts(request): + query = request.GET.get('query', '') + category_id = request.GET.get('category', 0) + categories = Category.objects.all() + posts = Post.objects.all() + + if category_id: + posts = posts.filter(category_id=category_id) + + if query: + posts = posts.filter(Q(titulo__icontains=query) | Q(texto__icontains=query)) + + return render(request, 'post/posts.html', { + 'posts': posts, + 'query': query, + 'categories': categories, + 'category_id': int(category_id) + }) + +def post_detail(request, post_id): + post = get_object_or_404(Post, id=post_id) + comments = Comment.objects.filter(post=post) + + if request.method == 'POST': + comment_form = CommentForm(request.POST) + if comment_form.is_valid(): + comment = comment_form.save(commit=False) + comment.post = post + comment.user = request.user # ou qualquer método que você usa para obter o usuário atual + comment.save() + else: + comment_form = CommentForm() + + return render(request, 'post_detail.html', {'post': post, 'comments': comments, 'comment_form': comment_form}) + +def detail(request, pk): + post = get_object_or_404(Post, pk=pk) + + if request.method == 'POST': + comment_form = CommentForm(request.POST) + if comment_form.is_valid(): + comment = comment_form.save(commit=False) + comment.post = post + comment.user = request.user + comment.save() + else: + comment_form = CommentForm() + + comments = Comment.objects.filter(post=post) + + return render(request, 'post.html', { + 'post': post, + 'comments': comments, + 'comment_form': comment_form, + }) + + +@login_required +def new(request): + if request.method == 'POST': + form = NewPostForm(request.POST, request.FILES) + + if form.is_valid(): + post = form.save(commit=False) + post.created_by = request.user + post.save() + + return redirect('post:detail', pk=post.id) + else: + form = NewPostForm() + + return render(request, 'create_post.html', { + 'form': form, + 'title': 'New post', + }) + +@login_required +def edit(request, pk): + post = get_object_or_404(Post, pk=pk, created_by=request.user) + + if request.method == 'POST': + form = EditPostForm(request.POST, request.FILES, instance=post) + + if form.is_valid(): + form.save() + + return redirect('post:detail', pk=post.id) + else: + form = EditPostForm(instance=post) + + return render(request, 'post.html', { + 'form': form, + 'title': 'Edit post', + }) + +@login_required +def delete(request, pk): + post = get_object_or_404(Post, pk=pk, created_by=request.user) + + if request.method == 'POST': + post.delete() + return redirect('core:brainwave') + + # Se o usuário não for o criador do post, levante uma exceção de permissão + raise PermissionDenied + +@login_required +def like_post(request, post_id): + post = get_object_or_404(Post, id=post_id) + + # Verifica se o usuário já curtiu o post + liked = post.likes.filter(id=request.user.id).exists() + + if liked: + post.likes.remove(request.user) + else: + post.likes.add(request.user) + + likes_count = post.likes.count() + + return JsonResponse({'liked': not liked, 'likes_count': likes_count}) + +@login_required +def like_comment(request, comment_id): + comment = get_object_or_404(Comment, id=comment_id) + + # Verifica se o usuário já curtiu o comentário + liked = comment.likes.filter(id=request.user.id).exists() + + if liked: + comment.likes.remove(request.user) + else: + comment.likes.add(request.user) + + likes_count = comment.likes.count() + + return JsonResponse({'liked': not liked, 'likes_count': likes_count}) + +@login_required +def delete_comment(request, pk): + comment = get_object_or_404(Comment, pk=pk) + + # Verifica se o usuário logado é o autor do comentário + if request.user == comment.user: + comment.delete() + messages.success(request, 'Comentário excluído com sucesso.') + else: + messages.error(request, 'Você não tem permissão para excluir este comentário.') + + # Redireciona de volta à página do post ou para onde você desejar + return redirect('post:detail', pk=comment.post.pk) + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9d77084 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Django==4.2.7 +Pillow==10.1.0 \ No newline at end of file