first commit

This commit is contained in:
pacnpal
2024-10-28 17:09:57 -04:00
commit 2e1b4d7af7
9993 changed files with 1182741 additions and 0 deletions

0
reviews/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

99
reviews/admin.py Normal file
View File

@@ -0,0 +1,99 @@
from django.contrib import admin
from django.utils.html import format_html
from .models import Review, ReviewImage, ReviewLike, ReviewReport
class ReviewImageInline(admin.TabularInline):
model = ReviewImage
extra = 1
fields = ('image', 'caption', 'order')
@admin.register(Review)
class ReviewAdmin(admin.ModelAdmin):
list_display = ('get_title', 'user', 'rating', 'created_at', 'is_published', 'get_reports_count')
list_filter = ('is_published', 'rating', 'created_at')
search_fields = ('user__username', 'content', 'title')
readonly_fields = ('created_at', 'updated_at')
actions = ['publish_reviews', 'unpublish_reviews']
inlines = [ReviewImageInline]
fieldsets = (
('Review Details', {
'fields': (('user', 'rating'), 'title', 'content')
}),
('Review Target', {
'fields': (('content_type', 'object_id'),)
}),
('Moderation', {
'fields': ('is_published', 'moderation_notes', 'moderated_by', 'moderated_at')
}),
('Metadata', {
'fields': ('created_at', 'updated_at', 'visit_date'),
'classes': ('collapse',)
}),
)
def get_title(self, obj):
return f"Review of {obj.content_object}"
get_title.short_description = 'Review Title'
def get_reports_count(self, obj):
count = obj.reports.filter(resolved=False).count()
if count > 0:
return format_html(
'<span style="color: {};">{}</span>',
'red' if count > 2 else 'orange',
count
)
return count
get_reports_count.short_description = 'Reports'
def publish_reviews(self, request, queryset):
queryset.update(is_published=True)
publish_reviews.short_description = "Publish selected reviews"
def unpublish_reviews(self, request, queryset):
queryset.update(is_published=False)
unpublish_reviews.short_description = "Unpublish selected reviews"
@admin.register(ReviewImage)
class ReviewImageAdmin(admin.ModelAdmin):
list_display = ('review', 'caption', 'order')
list_filter = ('review__created_at',)
search_fields = ('review__title', 'caption')
ordering = ('review', 'order')
@admin.register(ReviewLike)
class ReviewLikeAdmin(admin.ModelAdmin):
list_display = ('review', 'user', 'created_at')
list_filter = ('created_at',)
search_fields = ('review__title', 'user__username')
readonly_fields = ('created_at',)
@admin.register(ReviewReport)
class ReviewReportAdmin(admin.ModelAdmin):
list_display = ('review', 'user', 'created_at', 'resolved', 'resolved_by')
list_filter = ('resolved', 'created_at')
search_fields = ('review__title', 'user__username', 'reason')
readonly_fields = ('created_at', 'resolved_at')
actions = ['mark_resolved', 'mark_unresolved']
fieldsets = (
('Report Details', {
'fields': ('review', 'user', 'reason')
}),
('Resolution', {
'fields': ('resolved', 'resolved_by', 'resolution_notes', 'resolved_at')
}),
('Metadata', {
'fields': ('created_at',),
'classes': ('collapse',)
}),
)
def mark_resolved(self, request, queryset):
queryset.update(resolved=True, resolved_by=request.user)
mark_resolved.short_description = "Mark selected reports as resolved"
def mark_unresolved(self, request, queryset):
queryset.update(resolved=False, resolved_by=None, resolution_notes='')
mark_unresolved.short_description = "Mark selected reports as unresolved"

8
reviews/apps.py Normal file
View File

@@ -0,0 +1,8 @@
from django.apps import AppConfig
class ReviewsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'reviews'
def ready(self):
import reviews.signals # noqa

View File

@@ -0,0 +1,88 @@
# Generated by Django 5.1.2 on 2024-10-28 20:17
import django.core.validators
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Review',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('rating', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(10)])),
('title', models.CharField(max_length=200)),
('content', models.TextField()),
('visit_date', models.DateField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('is_published', models.BooleanField(default=True)),
('moderation_notes', models.TextField(blank=True)),
('moderated_at', models.DateTimeField(blank=True, null=True)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('moderated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='moderated_reviews', to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='ReviewImage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('image', models.ImageField(upload_to='review_images/')),
('caption', models.CharField(blank=True, max_length=200)),
('order', models.PositiveIntegerField(default=0)),
('review', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='reviews.review')),
],
options={
'ordering': ['order'],
},
),
migrations.CreateModel(
name='ReviewLike',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('review', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to='reviews.review')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='review_likes', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='ReviewReport',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('reason', models.TextField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('resolved', models.BooleanField(default=False)),
('resolution_notes', models.TextField(blank=True)),
('resolved_at', models.DateTimeField(blank=True, null=True)),
('resolved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='resolved_review_reports', to=settings.AUTH_USER_MODEL)),
('review', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reports', to='reviews.review')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='review_reports', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-created_at'],
},
),
migrations.AddIndex(
model_name='review',
index=models.Index(fields=['content_type', 'object_id'], name='reviews_rev_content_627d80_idx'),
),
migrations.AlterUniqueTogether(
name='reviewlike',
unique_together={('review', 'user')},
),
]

View File

113
reviews/models.py Normal file
View File

@@ -0,0 +1,113 @@
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.validators import MinValueValidator, MaxValueValidator
class Review(models.Model):
# Generic relation to allow reviews on different types (rides, parks)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
# Review details
user = models.ForeignKey(
'accounts.User',
on_delete=models.CASCADE,
related_name='reviews'
)
rating = models.PositiveSmallIntegerField(
validators=[MinValueValidator(1), MaxValueValidator(10)]
)
title = models.CharField(max_length=200)
content = models.TextField()
visit_date = models.DateField()
# Metadata
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# Moderation
is_published = models.BooleanField(default=True)
moderation_notes = models.TextField(blank=True)
moderated_by = models.ForeignKey(
'accounts.User',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='moderated_reviews'
)
moderated_at = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['content_type', 'object_id']),
]
def __str__(self):
return f"Review of {self.content_object} by {self.user.username}"
class ReviewImage(models.Model):
review = models.ForeignKey(
Review,
on_delete=models.CASCADE,
related_name='images'
)
image = models.ImageField(upload_to='review_images/')
caption = models.CharField(max_length=200, blank=True)
order = models.PositiveIntegerField(default=0)
class Meta:
ordering = ['order']
def __str__(self):
return f"Image {self.order + 1} for {self.review}"
class ReviewLike(models.Model):
review = models.ForeignKey(
Review,
on_delete=models.CASCADE,
related_name='likes'
)
user = models.ForeignKey(
'accounts.User',
on_delete=models.CASCADE,
related_name='review_likes'
)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ['review', 'user']
def __str__(self):
return f"{self.user.username} likes {self.review}"
class ReviewReport(models.Model):
review = models.ForeignKey(
Review,
on_delete=models.CASCADE,
related_name='reports'
)
user = models.ForeignKey(
'accounts.User',
on_delete=models.CASCADE,
related_name='review_reports'
)
reason = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
resolved = models.BooleanField(default=False)
resolved_by = models.ForeignKey(
'accounts.User',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='resolved_review_reports'
)
resolution_notes = models.TextField(blank=True)
resolved_at = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return f"Report on {self.review} by {self.user.username}"

0
reviews/signals.py Normal file
View File

3
reviews/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

7
reviews/urls.py Normal file
View File

@@ -0,0 +1,7 @@
from django.urls import path
from . import views
app_name = 'reviews'
urlpatterns = [
]

3
reviews/views.py Normal file
View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.