• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gcivil-nyu-org / team2-wed-spring25 / 775

16 Apr 2025 09:16PM UTC coverage: 1.934% (-0.3%) from 2.27%
775

push

travis-pro

nalinir
Changes up to 4/16

2 of 2 new or added lines in 1 file covered. (100.0%)

27 existing lines in 1 file now uncovered.

53 of 2741 relevant lines covered (1.93%)

0.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/backend/nightwalkers/accounts/models.py
1
from django.db import models
×
2
from django.contrib.auth.models import AbstractUser, BaseUserManager
×
3
from django.db.models import Q
×
4

5

6
class CustomUserManager(BaseUserManager):
×
7

8
    def create_user(self, email, first_name, last_name, password=None, **extra_fields):
9
        if not email:
10
            raise ValueError("Users must have an email address")
11
        if not first_name:
12
            raise ValueError("Users must have a first name")
13
        if not last_name:
14
            raise ValueError("Users must have a last name")
15

16
        email = self.normalize_email(email)
17
        user = self.model(
18
            email=email, first_name=first_name, last_name=last_name, **extra_fields
19
        )
20
        user.set_password(password)
21
        user.save(using=self._db)
22
        return user
23

24
    def create_superuser(self, email, password=None, **extra_fields):
25
        extra_fields.setdefault("is_staff", True)
26
        extra_fields.setdefault("is_superuser", True)
27
        extra_fields.setdefault("is_admin", True)
28
        extra_fields.setdefault("is_active", True)
29
        extra_fields.setdefault("email_verified", True)
30
        extra_fields.setdefault("first_name", "Admin")
31
        extra_fields.setdefault("last_name", "User")
32
        return self.create_user(email, password=password, **extra_fields)
33

34

35
class User(AbstractUser):
×
36
    username = None
×
37
    email = models.EmailField(unique=True, db_index=True)
×
38
    first_name = models.CharField(max_length=150, blank=False, null=False)
×
39
    last_name = models.CharField(max_length=150, blank=False, null=False)
×
40
    email_verified = models.BooleanField(default=False)
×
41
    is_admin = models.BooleanField(default=False)
×
42
    is_staff = models.BooleanField(default=False)
×
43
    is_active = models.BooleanField(default=True)
×
44
    date_joined = models.DateTimeField(auto_now_add=True)
×
45
    provider = models.CharField(max_length=50, blank=True)
×
46
    provider_id = models.CharField(max_length=100, blank=True)
×
47
    avatar = models.ImageField(upload_to="avatars/", blank=True, null=True)
×
48
    avatar_url = models.URLField(blank=True, null=True, max_length=1024)
×
49
    karma = models.IntegerField(default=0)
×
UNCOV
50
    is_banned = models.BooleanField(
×
51
        default=False, verbose_name="Is the user banned", null=True, blank=True
52
    )
53

54
    # Many-to-Many relationship for followers/following
UNCOV
55
    following = models.ManyToManyField(
×
56
        "self",  # Reference to the same model
57
        through="Follow",  # Use the Follow model as the intermediary
58
        symmetrical=False,
59
        # Relationships are not symmetrical (A follows B ≠ B follows A)
60
        related_name="followers",  # Reverse accessor for followers
61
    )
62

UNCOV
63
    objects = CustomUserManager()
×
64
    USERNAME_FIELD = "email"
×
65
    REQUIRED_FIELDS = ["first_name", "last_name"]
×
66

67
    def __str__(self):
×
68
        return f"{self.get_full_name()} ({self.email}) {self.get_karma()}"
×
69

70
    def get_user_karma(self):
×
71
        return self.karma
×
72

73
    def get_full_name(self):
×
74
        return f"{self.first_name} {self.last_name}"
×
75

76
    def get_short_name(self):
×
77
        return self.first_name
×
78

79
    def has_verified_email(self):
×
80
        return self.email_verified
×
81

82
    def get_provider(self):
×
83
        return self.provider if self.provider else "email"
×
84

85
    def get_avatar_url(self):
×
86
        return self.avatar_url if self.avatar_url else None
×
87

88
    def get_user_id(self):
×
89
        return self.id if self.id else None
×
90

91
    def get_karma(self):
×
92
        return self.karma if self.karma else 0
×
93

UNCOV
94
    @property
×
UNCOV
95
    def get_avatar(self):
×
96
        """
97
            Returns the user avatar either uploaded \
98
            (if we end up supporting this but thought\
99
            I would add this now) or for now OAuth avatar
100
        """
101
        if self.avatar:
×
102
            return self.avatar.url
×
UNCOV
103
        elif self.avatar_url:
×
104
            return self.avatar_url
×
105
        return None
×
106

107
    def get_followers_count(self):
×
108
        return self.followers.count()
×
109

110
    def get_following_count(self):
×
UNCOV
111
        return self.following.count()
×
112

UNCOV
113
    def is_following(self, user):
×
114
        """Check if the current user is following the given user."""
UNCOV
115
        return self.following.filter(id=user.id).exists()
×
116

UNCOV
117
    def is_followed_by(self, user):
×
118
        """Check if the current user is followed by the given user."""
UNCOV
119
        return self.followers.filter(id=user.id).exists()
×
120

UNCOV
121
    def is_mutual_follow(self, user):
×
122
        """Check if both users follow each other."""
UNCOV
123
        return self.is_following(user) and self.is_followed_by(user)
×
124

UNCOV
125
    def get_saved_routes_count(self):
×
126
        """Returns the count of saved routes for this user"""
UNCOV
127
        return self.saved_routes.count()
×
128

UNCOV
129
    def get_mutual_follows(self):
×
130
        """
131
        Returns all users who follow the current user AND are followed by them.
132
        (Uses a single DB query for efficiency)
133
        """
134
        return User.objects.filter(Q(followers=self) & Q(following=self))
×
135

136

UNCOV
137
class Follow(models.Model):
×
138
    # Main user (the one who is following)
UNCOV
139
    main_user = models.ForeignKey(
×
140
        User,
141
        on_delete=models.CASCADE,
142
        related_name="main_user_following",
143
        db_index=True,  # Add index
144
    )
145
    # User being followed
UNCOV
146
    following_user = models.ForeignKey(
×
147
        User,
148
        on_delete=models.CASCADE,
149
        related_name="following_user_followers",
150
        db_index=True,  # Add index
151
    )
152
    # Timestamp for when the follow relationship was created
UNCOV
153
    created_at = models.DateTimeField(auto_now_add=True)
×
154

UNCOV
155
    class Meta:
×
156
        # Ensure unique follow relationships
UNCOV
157
        unique_together = ("main_user", "following_user")
×
158
        # Order by creation time
159
        ordering = ["-created_at"]
×
160

UNCOV
161
    def __str__(self):
×
162
        return f"{self.main_user} follows {self.following_user}"
×
163

164

165
class ReportIssue(models.Model):
×
166
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
×
UNCOV
167
    reported_at = models.DateTimeField(auto_now_add=True)
×
168
    title = models.CharField(max_length=100, null=False)
×
169
    description = models.TextField(null=False, max_length=500)
×
170

UNCOV
171
    def __str__(self):
×
172
        if self.user:
×
UNCOV
173
            return f"{self.title} by {self.user.first_name}"
×
174
        else:
UNCOV
175
            return f"{self.title} by Unknown User"
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc