updated to selfdelete inheritance

This commit is contained in:
2026-04-19 01:36:03 +02:00
parent 043e866ac9
commit 5280a87e8b
7 changed files with 151 additions and 58 deletions

View File

@@ -3,8 +3,21 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils import timezone
from vontor_cz.custom_fields import WebPImageField
from vontor_cz.models import SoftDeleteModel
class Chat(SoftDeleteModel):
AUTHOR_FIELD = 'owner'
class ChatType(models.TextChoices):
DM = 'DM', 'Direct Message'
GROUP = 'GROUP', 'Group'
chat_type = models.CharField(
max_length=10,
choices=ChatType.choices,
default=ChatType.GROUP,
)
class Chat(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
@@ -50,11 +63,19 @@ class Chat(models.Model):
self.members.add(self.owner)
self.moderators.add(self.owner)
def clean(self):
if self.chat_type == self.ChatType.DM:
member_count = self.members.count() if self.pk else 0
if member_count > 2:
raise ValidationError("A DM chat cannot have more than 2 members.")
def __str__(self):
return f"Chat {self.id}"
class Message(models.Model):
class Message(SoftDeleteModel):
AUTHOR_FIELD = 'sender'
chat = models.ForeignKey(Chat, related_name='messages', on_delete=models.CASCADE)
sender = models.ForeignKey(
@@ -145,7 +166,7 @@ class Message(models.Model):
return f"Message {self.id} from {self.sender}"
class MessageHistory(models.Model):
class MessageHistory(SoftDeleteModel):
message = models.ForeignKey(
Message,
on_delete=models.CASCADE,
@@ -158,7 +179,7 @@ class MessageHistory(models.Model):
ordering = ['-archived_at']
class MessageReaction(models.Model):
class MessageReaction(SoftDeleteModel):
message = models.ForeignKey(
Message,
on_delete=models.CASCADE,
@@ -175,7 +196,7 @@ class MessageReaction(models.Model):
return f"{self.user} reacted {self.emoji}"
class MessageFile(models.Model):
class MessageFile(SoftDeleteModel):
message = models.ForeignKey(
Message,
on_delete=models.CASCADE,

View File

@@ -1,17 +1,6 @@
# Social Feature Ideas
## Hub
- Hub visibility flag (`is_public`) — private/public hubs
- Hub owner transfer (current owner passes ownership to another member)
## Chat
- Chat type field (DM vs group) — enforce 2-member limit on DMs
- Message soft-delete (`is_deleted` flag) — preserve reply context when a message is removed
## Posts
- Post reactions/likes — equivalent of MessageReaction but for posts
- Post comments — a `Comment` model FK-ing to `Post`
- Upvote/downvote system for posts — reddit style voting with score and sorting by "hotness"
## Users
- User blocking — affects message/post visibility across all social features
- ~~User blocking — affects message/post visibility across all social features~~ ✓ done (`UserBlock` in account, `has_blocked`/`is_blocked_by` helpers on CustomUser)

View File

@@ -1,11 +1,15 @@
import uuid
from django.db import models
from django.conf import settings
from vontor_cz.custom_fields import WebPImageField
from vontor_cz.models import SoftDeleteModel
# Create your models here.
class Hub(models.Model):
class Hub(SoftDeleteModel):
AUTHOR_FIELD = 'owner'
name = models.CharField(max_length=255, unique=True)
description = models.TextField(blank=True, null=True)
@@ -25,12 +29,45 @@ class Hub(models.Model):
blank=True
)
#TODO:
is_public = models.BooleanField(default=True)
transfer_to = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='pending_hub_transfers'
)
transfer_token = models.UUIDField(null=True, blank=True, unique=True)
def create_transfer(self, new_owner):
self.transfer_to = new_owner
self.transfer_token = uuid.uuid4()
self.save(update_fields=['transfer_to', 'transfer_token'])
def verify_transfer(self, input_token, triggering_user):
"""Requires uuid and triggering user must match the transfer_to field"""
if self.transfer_token and str(self.transfer_token) == str(input_token) and self.transfer_to == triggering_user:
self.owner = self.transfer_to
self.transfer_to = None
self.transfer_token = None
self.save(update_fields=['owner', 'transfer_to', 'transfer_token'])
return True
return raiseExceptions("Invalid transfer token or user does not match transfer_to field")
def cancel_transfer(self):
self.transfer_to = None
self.transfer_token = None
self.save(update_fields=['transfer_to', 'transfer_token'])
def __str__(self):
return self.name
class HubPermission(models.Model):
class HubPermission(SoftDeleteModel):
hub = models.ForeignKey(Hub, on_delete=models.CASCADE, related_name='moderators')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

View File

@@ -1,12 +1,14 @@
from django.db import models
from django.conf import settings
from vontor_cz.models import SoftDeleteModel
import magic
mime = magic.Magic(mime=True)
class Post(models.Model):
class Post(SoftDeleteModel):
AUTHOR_FIELD = 'author'
content = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -23,11 +25,19 @@ class Post(models.Model):
null=True,
blank=True
)
reply_to = models.ForeignKey(
'self',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='replies'
)
def __str__(self):
return f"Post {self.id}"
class PostContent(models.Model):
class PostContent(SoftDeleteModel):
post = models.ForeignKey(Post, related_name='contents', on_delete=models.CASCADE)
mime_type = models.CharField(max_length=100)
file = models.FileField(upload_to='post_contents/', null=True, blank=True) # For images/videos
@@ -39,4 +49,22 @@ class PostContent(models.Model):
def save(self, *args, **kwargs):
if self.file and not self.file._committed:
self.mime_type = mime.from_buffer(self.file.read(1024))
return super().save(*args, **kwargs)
return super().save(*args, **kwargs)
class PostVote(SoftDeleteModel):
class VoteChoice(models.IntegerChoices):
UP = 1, 'Upvote'
DOWN = -1, 'Downvote'
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='votes')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
vote = models.SmallIntegerField(choices=VoteChoice.choices)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ('post', 'user')
def __str__(self):
label = 'up' if self.vote == self.VoteChoice.UP else 'down'
return f"{self.user} voted {label} on Post {self.post_id}"