diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc
index 5be02db..ad5c32a 100644
Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ
diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc
index 28817aa..38479ac 100644
Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ
diff --git a/config/settings.py b/config/settings.py
index 291d043..0d1c507 100644
--- a/config/settings.py
+++ b/config/settings.py
@@ -149,11 +149,12 @@ STATIC_URL = 'static/'
# Collect static into a separate folder; avoid overlapping with STATICFILES_DIRS.
STATIC_ROOT = BASE_DIR / 'staticfiles'
-STATICFILES_DIRS = [
- BASE_DIR / 'static',
- BASE_DIR / 'assets',
- BASE_DIR / 'node_modules',
-]
+STATICFILES_DIRS = [BASE_DIR / "static"]
+
+MEDIA_URL = '/media/'
+MEDIA_ROOT = BASE_DIR / 'media'
+
+
# Email
EMAIL_BACKEND = os.getenv(
diff --git a/config/urls.py b/config/urls.py
index bcfc074..cb9e1cf 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -15,14 +15,14 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
-from django.urls import include, path
-from django.conf import settings
+from django.urls import path, include
from django.conf.urls.static import static
+from django.conf import settings
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("core.urls")),
-]
+] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG:
urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets")
diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc
new file mode 100644
index 0000000..d64a49e
Binary files /dev/null and b/core/__pycache__/forms.cpython-311.pyc differ
diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc
index 9aa598b..07bf217 100644
Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ
diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc
index 1f807fa..586bc21 100644
Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ
diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc
index 6867ddf..1a7d9bc 100644
Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ
diff --git a/core/forms.py b/core/forms.py
new file mode 100644
index 0000000..686e88b
--- /dev/null
+++ b/core/forms.py
@@ -0,0 +1,7 @@
+from django import forms
+from .models import MediaUpload
+
+class MediaUploadForm(forms.ModelForm):
+ class Meta:
+ model = MediaUpload
+ fields = ['title', 'image', 'measurements']
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
new file mode 100644
index 0000000..46aef45
--- /dev/null
+++ b/core/migrations/0001_initial.py
@@ -0,0 +1,24 @@
+# Generated by Django 5.2.7 on 2025-12-16 01:52
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='MediaUpload',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(blank=True, max_length=255)),
+ ('image', models.ImageField(upload_to='uploads/')),
+ ('measurements', models.CharField(blank=True, max_length=255)),
+ ('uploaded_at', models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ ]
diff --git a/core/migrations/0002_rating.py b/core/migrations/0002_rating.py
new file mode 100644
index 0000000..6b1ea0c
--- /dev/null
+++ b/core/migrations/0002_rating.py
@@ -0,0 +1,27 @@
+# Generated by Django 5.2.7 on 2025-12-16 01:54
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0001_initial'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Rating',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('score', models.IntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')])),
+ ('comment', models.TextField(blank=True)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('media_upload', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ratings', to='core.mediaupload')),
+ ('rater', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc
new file mode 100644
index 0000000..49e8098
Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ
diff --git a/core/migrations/__pycache__/0002_rating.cpython-311.pyc b/core/migrations/__pycache__/0002_rating.cpython-311.pyc
new file mode 100644
index 0000000..1d16b68
Binary files /dev/null and b/core/migrations/__pycache__/0002_rating.cpython-311.pyc differ
diff --git a/core/models.py b/core/models.py
index 71a8362..93de57f 100644
--- a/core/models.py
+++ b/core/models.py
@@ -1,3 +1,21 @@
from django.db import models
+from django.contrib.auth.models import User
-# Create your models here.
+class MediaUpload(models.Model):
+ title = models.CharField(max_length=255, blank=True)
+ image = models.ImageField(upload_to='uploads/')
+ measurements = models.CharField(max_length=255, blank=True)
+ uploaded_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return self.title or str(self.uploaded_at)
+
+class Rating(models.Model):
+ media_upload = models.ForeignKey(MediaUpload, on_delete=models.CASCADE, related_name='ratings')
+ score = models.IntegerField(choices=[(i, str(i)) for i in range(1, 6)])
+ comment = models.TextField(blank=True)
+ rater = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return f'{self.media_upload.title or self.media_upload.id} - {self.score}'
\ No newline at end of file
diff --git a/core/templates/base.html b/core/templates/base.html
index 1e7e5fb..aaf6432 100644
--- a/core/templates/base.html
+++ b/core/templates/base.html
@@ -3,7 +3,10 @@
- {% block title %}Knowledge Base{% endblock %}
+ {% block title %}Savage Ratings{% endblock %}
+
+
+
{% if project_description %}
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index faec813..9bd28db 100644
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -1,145 +1,18 @@
-{% extends "base.html" %}
+{% extends 'base.html' %}
+{% load static %}
-{% block title %}{{ project_name }}{% endblock %}
-
-{% block head %}
-
-
-
-
-{% endblock %}
+{% block title %}Savage Ratings{% endblock %}
{% block content %}
-
-
-
Analyzing your requirements and generating your app…
-
-
Loading…
+
+
+
Get Brutally Honest Ratings
+
Upload your images and videos to get savage ratings from our panel.
+
-
AppWizzy AI is collecting your requirements and applying the first changes.
-
This page will refresh automatically as the plan is implemented.
-
- Runtime: Django {{ django_version }} · Python {{ python_version }}
- — UTC {{ current_time|date:"Y-m-d H:i:s" }}
-
-
-
-
-{% endblock %}
\ No newline at end of file
+
+{% endblock %}
diff --git a/core/templates/core/media_detail.html b/core/templates/core/media_detail.html
new file mode 100644
index 0000000..d40ea1a
--- /dev/null
+++ b/core/templates/core/media_detail.html
@@ -0,0 +1,58 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block title %}{{ media.title|default:"Media Detail" }}{% endblock %}
+
+{% block content %}
+
+
{{ media.title }}
+

+ {% if media.measurements %}
+
Measurements: {{ media.measurements }}
+ {% endif %}
+
Back to home
+
+
+
Rate this media
+
+
+ {% if average_rating is not None %}
+
Average Rating: {{ average_rating|floatformat:1 }} / 5
+ {% else %}
+
No ratings yet.
+ {% endif %}
+
+ {% if ratings %}
+
+ {% endif %}
+
+
+{% endblock %}
diff --git a/core/urls.py b/core/urls.py
index 6299e3d..95d94d5 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -1,7 +1,8 @@
from django.urls import path
-
-from .views import home
+from .views import index, media_detail, rate_media
urlpatterns = [
- path("", home, name="home"),
-]
+ path('', index, name='index'),
+ path('media/
/', media_detail, name='media_detail'),
+ path('media//rate/', rate_media, name='rate_media'),
+]
\ No newline at end of file
diff --git a/core/views.py b/core/views.py
index c9aed12..b49e5db 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,25 +1,34 @@
-import os
-import platform
+from django.shortcuts import render, redirect
+from django.db.models import Avg
+from .forms import MediaUploadForm
+from .models import MediaUpload, Rating
-from django import get_version as django_version
-from django.shortcuts import render
-from django.utils import timezone
+def index(request):
+ if request.method == 'POST':
+ form = MediaUploadForm(request.POST, request.FILES)
+ if form.is_valid():
+ media_upload = form.save()
+ return redirect('media_detail', pk=media_upload.pk)
+ else:
+ form = MediaUploadForm()
+ return render(request, 'core/index.html', {'form': form})
+def media_detail(request, pk):
+ media = MediaUpload.objects.get(pk=pk)
+ ratings = media.ratings.all()
+ average_rating = ratings.aggregate(Avg('score'))['score__avg']
+ return render(request, 'core/media_detail.html', {'media': media, 'ratings': ratings, 'average_rating': average_rating})
-def home(request):
- """Render the landing screen with loader and environment details."""
- host_name = request.get_host().lower()
- agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
- now = timezone.now()
+def rate_media(request, pk):
+ if request.method == 'POST':
+ media_upload = MediaUpload.objects.get(pk=pk)
+ score = request.POST.get('score')
+ comment = request.POST.get('comment', '')
+ if request.user.is_authenticated:
+ rater = request.user
+ else:
+ rater = None
- context = {
- "project_name": "New Style",
- "agent_brand": agent_brand,
- "django_version": django_version(),
- "python_version": platform.python_version(),
- "current_time": now,
- "host_name": host_name,
- "project_description": os.getenv("PROJECT_DESCRIPTION", ""),
- "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
- }
- return render(request, "core/index.html", context)
+ if score:
+ Rating.objects.create(media_upload=media_upload, score=score, comment=comment, rater=rater)
+ return redirect('media_detail', pk=pk)
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index e22994c..e51ac05 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
Django==5.2.7
+Pillow==12.0.0
mysqlclient==2.2.7
python-dotenv==1.1.1
diff --git a/static/css/custom.css b/static/css/custom.css
index 925f6ed..d531ff1 100644
--- a/static/css/custom.css
+++ b/static/css/custom.css
@@ -1,4 +1,94 @@
-/* Custom styles for the application */
body {
- font-family: system-ui, -apple-system, sans-serif;
+ background-color: #1A1A1A;
+ color: #F5F5F5;
+ font-family: 'Lato', sans-serif;
}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: 'Roboto', sans-serif;
+}
+
+.hero {
+ background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
+ padding: 100px 0;
+ text-align: center;
+}
+
+.hero h1 {
+ font-size: 4rem;
+ font-weight: 700;
+}
+
+.btn-primary {
+ background-color: #FF3B30;
+ border-color: #FF3B30;
+}
+
+.btn-primary:hover {
+ background-color: #E6352A;
+ border-color: #E6352A;
+}
+
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+form p {
+ margin-bottom: 15px;
+}
+
+form input[type='text'], form input[type='file'] {
+ width: 100%;
+ padding: 10px;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+}
+
+.rating-section {
+ margin-top: 40px;
+ padding: 20px;
+ background-color: #2a2a2a;
+ border-radius: 8px;
+}
+
+.rating-section h2, .rating-section h3 {
+ color: #F5F5F5;
+ margin-bottom: 20px;
+}
+
+.form-label {
+ color: #F5F5F5;
+}
+
+.form-control {
+ background-color: #3a3a3a;
+ color: #F5F5F5;
+ border: 1px solid #555;
+}
+
+.form-control:focus {
+ background-color: #4a4a4a;
+ color: #F5F5F5;
+ border-color: #FF3B30;
+ box-shadow: 0 0 0 0.25rem rgba(255, 59, 48, 0.25);
+}
+
+.comments-section {
+ margin-top: 30px;
+}
+
+.comments-section .card {
+ background-color: #333;
+ border: 1px solid #444;
+ color: #F5F5F5;
+}
+
+.comments-section .card-title {
+ color: #FF3B30;
+}
+
+.comments-section .text-muted {
+ color: #bbb !important;
+}
\ No newline at end of file
diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css
index 108056f..d531ff1 100644
--- a/staticfiles/css/custom.css
+++ b/staticfiles/css/custom.css
@@ -1,21 +1,94 @@
-
-:root {
- --bg-color-start: #6a11cb;
- --bg-color-end: #2575fc;
- --text-color: #ffffff;
- --card-bg-color: rgba(255, 255, 255, 0.01);
- --card-border-color: rgba(255, 255, 255, 0.1);
-}
body {
- margin: 0;
- font-family: 'Inter', sans-serif;
- background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
- color: var(--text-color);
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 100vh;
- text-align: center;
- overflow: hidden;
- position: relative;
+ background-color: #1A1A1A;
+ color: #F5F5F5;
+ font-family: 'Lato', sans-serif;
}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: 'Roboto', sans-serif;
+}
+
+.hero {
+ background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
+ padding: 100px 0;
+ text-align: center;
+}
+
+.hero h1 {
+ font-size: 4rem;
+ font-weight: 700;
+}
+
+.btn-primary {
+ background-color: #FF3B30;
+ border-color: #FF3B30;
+}
+
+.btn-primary:hover {
+ background-color: #E6352A;
+ border-color: #E6352A;
+}
+
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+form p {
+ margin-bottom: 15px;
+}
+
+form input[type='text'], form input[type='file'] {
+ width: 100%;
+ padding: 10px;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+}
+
+.rating-section {
+ margin-top: 40px;
+ padding: 20px;
+ background-color: #2a2a2a;
+ border-radius: 8px;
+}
+
+.rating-section h2, .rating-section h3 {
+ color: #F5F5F5;
+ margin-bottom: 20px;
+}
+
+.form-label {
+ color: #F5F5F5;
+}
+
+.form-control {
+ background-color: #3a3a3a;
+ color: #F5F5F5;
+ border: 1px solid #555;
+}
+
+.form-control:focus {
+ background-color: #4a4a4a;
+ color: #F5F5F5;
+ border-color: #FF3B30;
+ box-shadow: 0 0 0 0.25rem rgba(255, 59, 48, 0.25);
+}
+
+.comments-section {
+ margin-top: 30px;
+}
+
+.comments-section .card {
+ background-color: #333;
+ border: 1px solid #444;
+ color: #F5F5F5;
+}
+
+.comments-section .card-title {
+ color: #FF3B30;
+}
+
+.comments-section .text-muted {
+ color: #bbb !important;
+}
\ No newline at end of file
Comments:
+ {% for rating in ratings %} +Score: {{ rating.score }}
+ {% if rating.comment %} +{{ rating.comment }}
+ {% endif %} +By {% if rating.rater %}{{ rating.rater.username }}{% else %}Anonymous{% endif %} on {{ rating.created_at|date:"M d, Y H:i" }}
+