from django.db import models from django.contrib.auth.models import User from taggit.managers import TaggableManager import secrets class Team(models.Model): name = models.CharField(max_length=255) description = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) members = models.ManyToManyField(User, through='TeamMembership', related_name='teams') def __str__(self): return self.name class TeamMembership(models.Model): ROLE_CHOICES = [ ('OWNER', 'Owner'), ('ADMIN', 'Admin'), ('MEMBER', 'Member'), ] user = models.ForeignKey(User, on_delete=models.CASCADE) team = models.ForeignKey(Team, on_delete=models.CASCADE) role = models.CharField(max_length=10, choices=ROLE_CHOICES, default='MEMBER') joined_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('user', 'team') class Bookmark(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bookmarks') url = models.URLField(max_length=1000) title = models.CharField(max_length=255, blank=True) notes = models.TextField(blank=True) is_favorite = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) tags = TaggableManager() def __str__(self): return self.title or self.url class BookmarkShare(models.Model): bookmark = models.ForeignKey(Bookmark, on_delete=models.CASCADE, related_name='shares') team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='shared_bookmarks') shared_by = models.ForeignKey(User, on_delete=models.CASCADE) shared_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('bookmark', 'team') class Extraction(models.Model): bookmark = models.OneToOneField(Bookmark, on_delete=models.CASCADE, related_name='extraction') content_html = models.TextField(blank=True) content_text = models.TextField(blank=True) metadata = models.JSONField(default=dict, blank=True) extracted_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Extraction for {self.bookmark}" class Summary(models.Model): bookmark = models.OneToOneField(Bookmark, on_delete=models.CASCADE, related_name='summary') content = models.TextField() generated_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Summary for {self.bookmark}" class APIToken(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='api_tokens') token = models.CharField(max_length=64, unique=True, editable=False) name = models.CharField(max_length=255, help_text="A recognizable name for this token (e.g. 'Mobile App')", default="Default Token") created_at = models.DateTimeField(auto_now_add=True) last_used_at = models.DateTimeField(null=True, blank=True) is_active = models.BooleanField(default=True) def save(self, *args, **kwargs): if not self.token: self.token = secrets.token_hex(20) super().save(*args, **kwargs) def __str__(self): return f"{self.name} - {self.user.username}"