diff --git a/db.sqlite3 b/db.sqlite3
index 080ea3f6..7f81c064 100644
Binary files a/db.sqlite3 and b/db.sqlite3 differ
diff --git a/filme/admin.py b/filme/admin.py
index 23043cc1..655d2eba 100644
--- a/filme/admin.py
+++ b/filme/admin.py
@@ -1,6 +1,17 @@
from django.contrib import admin
-from .models import Filme, Episodio
+from .models import Filme, Episodio, Usuario
+from django.contrib.auth.admin import UserAdmin
+
+# Os campos do UserAdmin são tuplas, desta forma transformei em lista python para incluir o novo campo
+# de filmes vistos.
+campos = list(UserAdmin.fieldsets)
+campos.append(
+ ("Histórico", {'fields': ('filmes_vistos',)})
+)
+
+UserAdmin.fieldsets = tuple(campos)
# Register your models here.
admin.site.register(Filme)
admin.site.register(Episodio)
+admin.site.register(Usuario, UserAdmin)
diff --git a/filme/migrations/0001_initial.py b/filme/migrations/0001_initial.py
index 4ea379f5..9bd6067a 100644
--- a/filme/migrations/0001_initial.py
+++ b/filme/migrations/0001_initial.py
@@ -1,6 +1,9 @@
-# Generated by Django 4.2.5 on 2023-09-06 01:07
+# Generated by Django 4.2.5 on 2023-09-24 16:11
+import django.contrib.auth.models
+import django.contrib.auth.validators
from django.db import migrations, models
+import django.db.models.deletion
import django.utils.timezone
@@ -9,19 +12,56 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
+ ('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
- name='filme',
+ name='Filme',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('titulo', models.CharField(max_length=100)),
('thumb', models.ImageField(upload_to='thumb_filmes')),
('descricao', models.TextField(max_length=1000)),
- ('categoria', models.CharField(choices=[('ANALISES', 'Análises'), ('PROGRAMACAO', 'Programação'), ('APRESENTACAO', 'Apresentação'), ('OUTROS', 'Outros')], max_length=15)),
+ ('categoria', models.CharField(choices=[('ANALISES', 'Análises'), ('PROGRAMACAO', 'Programação'), ('APRESENTACAO', 'Apresentação'), ('OUTROS', 'Outros'), {'ANIMES', 'Animes'}], max_length=15)),
('visualizacoes', models.IntegerField(default=0)),
('data_criacao', models.DateTimeField(default=django.utils.timezone.now)),
],
),
+ migrations.CreateModel(
+ name='Episodio',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('titulo', models.CharField(max_length=100)),
+ ('video', models.URLField()),
+ ('filme', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='episodios', to='filme.filme')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Usuario',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('password', models.CharField(max_length=128, verbose_name='password')),
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+ ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
+ ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
+ ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('filmes_vistos', models.ManyToManyField(to='filme.filme')),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
+ ],
+ options={
+ 'verbose_name': 'user',
+ 'verbose_name_plural': 'users',
+ 'abstract': False,
+ },
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
]
diff --git a/filme/migrations/0002_alter_filme_categoria_episodio.py b/filme/migrations/0002_alter_filme_categoria_episodio.py
deleted file mode 100644
index dbd39b23..00000000
--- a/filme/migrations/0002_alter_filme_categoria_episodio.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Generated by Django 4.2.5 on 2023-09-17 17:32
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('filme', '0001_initial'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='filme',
- name='categoria',
- field=models.CharField(choices=[('ANALISES', 'Análises'), ('PROGRAMACAO', 'Programação'), ('APRESENTACAO', 'Apresentação'), ('OUTROS', 'Outros'), {'ANIMES', 'Animes'}], max_length=15),
- ),
- migrations.CreateModel(
- name='Episodio',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('titulo', models.CharField(max_length=100)),
- ('video', models.URLField()),
- ('filme', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='episodios', to='filme.filme')),
- ],
- ),
- ]
diff --git a/filme/models.py b/filme/models.py
index 7324a693..93ecc84a 100644
--- a/filme/models.py
+++ b/filme/models.py
@@ -1,16 +1,17 @@
from django.db import models
from django.utils import timezone
+from django.contrib.auth.models import AbstractUser
+
LISTA_CATEGORIAS = (
('ANALISES', 'Análises'),
('PROGRAMACAO', 'Programação'),
('APRESENTACAO', 'Apresentação'),
('OUTROS', 'Outros'),
- {'ANIMES', 'Animes'}
+ {'ANIMES', 'Animes'},
+ ['FILME_A', 'Filme de Ação'],
)
-# Create o film
-
class Filme(models.Model):
titulo = models.CharField(max_length=100)
@@ -26,8 +27,6 @@ class Filme(models.Model):
def __str__(self):
return self.titulo
-# Criar os episódios
-
class Episodio(models.Model):
# parametos do ForeignKey, "nome_da_tabela", related_name relaciona os episodios ao filme, on_delete se deletar o filme os episodios também sao deletados
@@ -39,4 +38,6 @@ class Episodio(models.Model):
def __str__(self):
return self.filme.titulo + ' - ' + self.titulo
-# Criar o usuário
+
+class Usuario(AbstractUser):
+ filmes_vistos = models.ManyToManyField('Filme')
diff --git a/filme/novos_context.py b/filme/novos_context.py
index 7c3a1350..e1bd594c 100644
--- a/filme/novos_context.py
+++ b/filme/novos_context.py
@@ -11,3 +11,12 @@ def lista_filmes_recentes(request):
def lista_filmes_emalta(request):
lista_filmes = Filme.objects.all().order_by('-visualizacoes')[0:10]
return {"lista_filmes_emalta": lista_filmes}
+
+
+def filme_destaque(request):
+ filme = Filme.objects.order_by('-data_criacao')
+ if filme:
+ filme = filme[0]
+ else:
+ filme = None
+ return {"filme_destaque": filme}
diff --git a/filme/templates/homefilmes.html b/filme/templates/homefilmes.html
index 844a9795..339f88de 100644
--- a/filme/templates/homefilmes.html
+++ b/filme/templates/homefilmes.html
@@ -12,24 +12,15 @@
{% block content %}
-
Esta é a HomeFilmes
-
-
-
-
+
- {{ object.titulo }}
+ {{ filme_destaque.titulo }}
- {{ object.descricao }}
+ {{ filme_destaque.descricao }}
@@ -78,6 +69,28 @@ Esta é a HomeFilmes
+
+
diff --git a/filme/templates/login.html b/filme/templates/login.html
new file mode 100644
index 00000000..3920204e
--- /dev/null
+++ b/filme/templates/login.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+
+{% block title %}
+ Login Hashflix
+{% endblock %}
+
+{% block head %}
+{% load static %}
+
+{% endblock %}
+
+{% block content %}
+
+
Login
+
+{% endblock %}
diff --git a/filme/templates/logout.html b/filme/templates/logout.html
new file mode 100644
index 00000000..5f28d069
--- /dev/null
+++ b/filme/templates/logout.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+
+{% block title %}
+ Logout Hashflix
+{% endblock %}
+
+{% block head %}
+{% load static %}
+
+{% endblock %}
+
+{% block content %}
+
+
Logout
+
+{% endblock %}
diff --git a/filme/templates/pesquisa.html b/filme/templates/pesquisa.html
new file mode 100644
index 00000000..6da2c0c0
--- /dev/null
+++ b/filme/templates/pesquisa.html
@@ -0,0 +1,26 @@
+{% extends 'base.html' %}
+
+{% block title %}
+ Pesquisa de Filmes
+{% endblock %}
+
+{% block head %}
+{% load static %}
+
+{% endblock %}
+
+{% block content %}
+
+
Resultados da busca
+
+ {% for filme in object_list %}
+
+ {% endfor %}
+
+
+{% endblock %}
diff --git a/filme/urls.py b/filme/urls.py
index 3899fb76..fb5c5a29 100644
--- a/filme/urls.py
+++ b/filme/urls.py
@@ -1,5 +1,6 @@
from django.urls import path, include
-from .views import Homepage, HomeFilmes, DetalhesFilme
+from .views import Homepage, HomeFilmes, DetalhesFilme, PesquisaFilme
+from django.contrib.auth import views as auth_view
app_name = 'filme'
@@ -9,4 +10,9 @@
path('', Homepage.as_view(), name='homepage'),
path('filmes/', HomeFilmes.as_view(), name='homefilmes'),
path('filmes/', DetalhesFilme.as_view(), name='detalhesfilme'),
+ path('pesquisa', PesquisaFilme.as_view(), name='pesquisafilme'),
+ path('login', auth_view.LoginView.as_view(
+ template_name='login.html'), name='login'),
+ path('logout', auth_view.LogoutView.as_view(
+ template_name='logout.html'), name='logout'),
]
diff --git a/filme/views.py b/filme/views.py
index ed39274d..a2afddf7 100644
--- a/filme/views.py
+++ b/filme/views.py
@@ -1,6 +1,7 @@
from django.shortcuts import render
from .models import Filme
from django.views.generic import TemplateView, ListView, DetailView
+from django.contrib.auth.mixins import LoginRequiredMixin
# Create your views here.
@@ -9,21 +10,21 @@ class Homepage(TemplateView):
template_name = 'homepage.html'
-class HomeFilmes(ListView):
+class HomeFilmes(LoginRequiredMixin, ListView):
template_name = "homefilmes.html"
model = Filme
-class DetalhesFilme(DetailView):
+class DetalhesFilme(LoginRequiredMixin, DetailView):
template_name = "detalhesfilme.html"
model = Filme
def get(self, request, *args, **kwargs):
- # Descobrir o filme acessado, Somar 1 nas visualizações do filme e atualizar no banco
filme = self.get_object()
- filme.visualizacoes += 1 # Editando o campo do banco de dados
- filme.save() # Salvando a atualização no banco de dados
-
+ filme.visualizacoes += 1
+ filme.save()
+ usuario = request.user # current user
+ usuario.filmes_vistos.add(filme) # .add para adicionar no banco
# Redireciona o usuário para a url final
return super().get(request, *args, **kwargs)
@@ -36,6 +37,24 @@ def get_context_data(self, **kwargs):
context['filmes_relacionados'] = filmes_relacionados
return context
+
+class PesquisaFilme(LoginRequiredMixin, ListView):
+ template_name = "pesquisa.html"
+ model = Filme
+
+ # Alterando o object_list
+
+ def get_queryset(self):
+ # Quando for feita uma pesquisa quero pegar o termo digitado
+ termo_pesquisa = self.request.GET.get(
+ 'query') # é o name do input da pesquisa
+ if termo_pesquisa:
+ object_list = self.model.objects.filter(
+ titulo__icontains=termo_pesquisa)
+ return object_list
+ else:
+ return None
+
# def homepage(request):
# return render(request, "homepage.html")
diff --git a/hashflix/settings.py b/hashflix/settings.py
index 1a83906a..7cafbfdd 100644
--- a/hashflix/settings.py
+++ b/hashflix/settings.py
@@ -66,6 +66,7 @@
'django.contrib.messages.context_processors.messages',
'filme.novos_context.lista_filmes_recentes',
'filme.novos_context.lista_filmes_emalta',
+ 'filme.novos_context.filme_destaque',
],
},
},
@@ -87,7 +88,7 @@
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
-
+AUTH_USER_MODEL = 'filme.Usuario'
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@@ -138,3 +139,8 @@
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
+# Gerenciamento de Users
+LOGIN_REDIRECT_URL = 'filme:homefilmes'
+
+LOGIN_URL = 'filme:login'
diff --git a/media/thumb_filmes/EXCEL_IMPRESSIONADOR_1280X725.png b/media/thumb_filmes/EXCEL_IMPRESSIONADOR_1280X725.png
deleted file mode 100644
index 252373fd..00000000
Binary files a/media/thumb_filmes/EXCEL_IMPRESSIONADOR_1280X725.png and /dev/null differ
diff --git a/media/thumb_filmes/JOGADOR1.jpg b/media/thumb_filmes/JOGADOR1.jpg
new file mode 100644
index 00000000..6ea6805f
Binary files /dev/null and b/media/thumb_filmes/JOGADOR1.jpg differ
diff --git a/media/thumb_filmes/blackclover.jpe b/media/thumb_filmes/blackclover.jpe
new file mode 100644
index 00000000..de81c7d3
Binary files /dev/null and b/media/thumb_filmes/blackclover.jpe differ
diff --git a/media/thumb_filmes/blackclover_Es5ps7i.jpe b/media/thumb_filmes/blackclover_Es5ps7i.jpe
new file mode 100644
index 00000000..de81c7d3
Binary files /dev/null and b/media/thumb_filmes/blackclover_Es5ps7i.jpe differ
diff --git a/media/thumb_filmes/deathnote.jpg b/media/thumb_filmes/deathnote.jpg
index f54caa18..aae0c27e 100644
Binary files a/media/thumb_filmes/deathnote.jpg and b/media/thumb_filmes/deathnote.jpg differ
diff --git a/media/thumb_filmes/deathnote_ydWhu4g.jpg b/media/thumb_filmes/deathnote_ydWhu4g.jpg
deleted file mode 100644
index aae0c27e..00000000
Binary files a/media/thumb_filmes/deathnote_ydWhu4g.jpg and /dev/null differ
diff --git a/media/thumb_filmes/demonslayer.jpg b/media/thumb_filmes/demonslayer.jpg
deleted file mode 100644
index cdc4833c..00000000
Binary files a/media/thumb_filmes/demonslayer.jpg and /dev/null differ
diff --git a/media/thumb_filmes/dragonball.png b/media/thumb_filmes/dragonball.png
deleted file mode 100644
index 53544aa4..00000000
Binary files a/media/thumb_filmes/dragonball.png and /dev/null differ
diff --git a/media/thumb_filmes/fairytail.jpe b/media/thumb_filmes/fairytail.jpe
new file mode 100644
index 00000000..3966b407
Binary files /dev/null and b/media/thumb_filmes/fairytail.jpe differ
diff --git a/media/thumb_filmes/fairytail.png b/media/thumb_filmes/fairytail.png
deleted file mode 100644
index af31034d..00000000
Binary files a/media/thumb_filmes/fairytail.png and /dev/null differ
diff --git a/media/thumb_filmes/kimetsu.jpe b/media/thumb_filmes/kimetsu.jpe
new file mode 100644
index 00000000..d6d5d30b
Binary files /dev/null and b/media/thumb_filmes/kimetsu.jpe differ
diff --git a/static/css/style_base.css b/static/css/style_base.css
index 3fdf84a1..38afb167 100644
--- a/static/css/style_base.css
+++ b/static/css/style_base.css
@@ -15,15 +15,15 @@ a {
color: #f5f4f1;
font-family: "Poppins", sans-serif;
}
-
+/* Style navbar */
.navbar {
position: fixed;
padding: 1rem;
width: 100%;
display: flex;
justify-content: space-between;
- align-items: center;
background-color: transparent;
+ align-items: center;
z-index: 50;
}
@@ -67,3 +67,13 @@ input[type="search"] {
padding: 0rem 0.3rem;
color: rgb(15, 15, 15);
}
+
+
+.nav-submit,
+.invisible {
+ display: none;
+}
+
+.navbar-bg {
+ background-color: rgb(0, 0, 0, 0.95);
+}
diff --git a/static/css/style_carousel.css b/static/css/style_carousel.css
index d0473a68..dc8eae07 100644
--- a/static/css/style_carousel.css
+++ b/static/css/style_carousel.css
@@ -15,6 +15,7 @@
gap: 0.5rem;
}
+.arrow-left3,
.arrow-left2,
.arrow-left,
.arrow-right {
@@ -45,12 +46,14 @@
);
}
+.arrow-left3:hover,
.arrow-left2:hover,
.arrow-right:hover,
.arrow-left:hover {
opacity: 1;
}
+.item3,
.item2,
.item {
height: 15rem;
@@ -60,6 +63,7 @@
transition: all 200ms ease-in-out;
}
+.current-item3,
.current-item2,
.current-item {
opacity: 1;
diff --git a/static/css/style_homefilmes.css b/static/css/style_homefilmes.css
index e29eff71..c4ebeedd 100644
--- a/static/css/style_homefilmes.css
+++ b/static/css/style_homefilmes.css
@@ -1,5 +1,6 @@
.content {
- padding-top: 4.68rem; /*Ajuste isso de acordo com a altura da sua barra de navegação */
+ display: flex;
+ flex-direction: column;
}
/* Inicio sec-filme */
@@ -24,6 +25,7 @@
padding: 1rem 1rem;
max-width: 30rem;
max-height: 5rem;
+ background-color: rgba(0, 0, 0, 0.4);
overflow: hidden; /* ... */
text-overflow: ellipsis;
white-space: nowrap;
@@ -34,7 +36,7 @@
margin: 1rem;
width: 5rem;
text-align: center;
- background-color: rgba(189, 16, 16, 0.527);
+ background-color: rgba(189, 16, 16);
color: rgba(255, 255, 255);
border-radius: 0.5rem;
transition: 1.02;
@@ -46,6 +48,7 @@
}
/* Outras sections */
+.sec-assistidos,
.sec-novo,
.sec-emalta {
padding: 2rem;
diff --git a/static/css/style_login.css b/static/css/style_login.css
new file mode 100644
index 00000000..e69de29b
diff --git a/static/css/style_logout.css b/static/css/style_logout.css
new file mode 100644
index 00000000..e69de29b
diff --git a/static/css/style_pesquisa.css b/static/css/style_pesquisa.css
new file mode 100644
index 00000000..46b411ec
--- /dev/null
+++ b/static/css/style_pesquisa.css
@@ -0,0 +1,22 @@
+.content{
+ padding-top: 4.68rem;
+ min-height: 100vh;
+}
+
+.search{
+ display: flex;
+ flex-flow: row wrap;
+ gap: 1rem;
+}
+
+.search-item{
+ display: flex;
+ flex-direction: column;
+}
+
+.item {
+ height: 15rem;
+ width: auto;
+ flex-shrink: 0; /* Para não diminuir para caber*/
+ opacity: 0.6;
+}
diff --git a/static/js/carousel.js b/static/js/carousel.js
index c2ad54e7..535d5621 100644
--- a/static/js/carousel.js
+++ b/static/js/carousel.js
@@ -63,3 +63,36 @@ controls2.forEach((control2) => {
items2[currentItem2].classList.add("current-item2");
});
});
+
+const controls3 = document.querySelectorAll(".control3");
+let currentItem3 = 0;
+const items3 = document.querySelectorAll(".item3");
+const maxItems3 = items3.length;
+
+controls3.forEach((control3) => {
+ control3.addEventListener("click", () => {
+ const isLeft3 = control3.classList.contains("arrow-left3");
+
+ if (isLeft3) {
+ currentItem3 -= 1;
+ } else {
+ currentItem3 += 1;
+ }
+
+ if (currentItem3 >= maxItems3) {
+ currentItem3 = 0;
+ }
+ // currentItem não pode ser < 0
+ if (currentItem3 < 0) {
+ currentItem3 = maxItems3 - 1;
+ }
+
+ items3.forEach((item3) => item3.classList.remove("current-item3"));
+ items3[currentItem3].scrollIntoView({
+ inline: "center",
+ behavior: "smooth",
+ });
+
+ items3[currentItem3].classList.add("current-item3");
+ });
+});
diff --git a/static/js/navbar.js b/static/js/navbar.js
new file mode 100644
index 00000000..0ea24e15
--- /dev/null
+++ b/static/js/navbar.js
@@ -0,0 +1,15 @@
+const nav = document.querySelector("nav"); //PEga a tag nav
+
+document.addEventListener("scroll", (e) => {
+ if (scrollY > 100) {
+ if (scrollY > window.innerHeight) {
+ nav.classList.add("invisible");
+ } else {
+ nav.classList.add("navbar-bg");
+ nav.classList.remove("invisible");
+ }
+ } else {
+ nav.classList.remove("navbar-bg");
+ nav.classList.remove("invisible");
+ }
+});
diff --git a/templates/base.html b/templates/base.html
index c56500c1..02918067 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -25,5 +25,7 @@
{% block content %}
{% endblock %}
{% include 'footer.html' %}
+
+