models.py 4.03 KB
Newer Older
1
2
"""
go/models.py
3

David Haynes's avatar
David Haynes committed
4
5
6
The core of Go: define the business logic through classes that represent
tables containing structured data in the database.
"""
David Haynes's avatar
David Haynes committed
7
8
9
# Python stdlib Imports
import string

10
# Django Imports
Jean Michel Rouly's avatar
Jean Michel Rouly committed
11
from django.contrib.auth.models import User
12
from django.core.cache import cache
13
from django.db import models
14
15
from django.db.models.signals import post_save
from django.dispatch import receiver
16
from django.utils import timezone
17
18

# Other Imports
19
from hashids import Hashids  # http://hashids.org/python/
20

21
# generate the salt and initialize Hashids
22
23
24
HASHIDS = Hashids(
    salt="srct.gmu.edu", alphabet=(string.ascii_lowercase + string.digits)
)
Jean Michel Rouly's avatar
Jean Michel Rouly committed
25

26
class RegisteredUser(models.Model):
27
    """
David Haynes's avatar
David Haynes committed
28
    This is simply a wrapper model for the User model which, if an object
David Haynes's avatar
David Haynes committed
29
    exists, indicates that that user is registered.
30
    """
31
    # Let's associate a User to this RegisteredUser
David Haynes's avatar
David Haynes committed
32
    user = models.OneToOneField(User, on_delete="cascade")
Jean Michel Rouly's avatar
Jean Michel Rouly committed
33

34
    # What is your name?
35
    full_name = models.CharField(
36
37
        blank=False,
        max_length=100,
38
    )
Jean Michel Rouly's avatar
Jean Michel Rouly committed
39

40
    # What organization are you associated with?
41
    organization = models.CharField(
42
43
        blank=False,
        max_length=100,
44
45
    )

46
    # Why do you want to use Go?
47
    description = models.TextField(blank=True)
48

49
    # Have you filled out the registration form?
50
    registered = models.BooleanField(default=False)
51

52
    # Are you approved to use Go?
53
    approved = models.BooleanField(default=False)
54

David Haynes's avatar
David Haynes committed
55
56
57
    # Is this User Blocked?
    blocked = models.BooleanField(default=False)

58
    def __str__(self):
David Haynes's avatar
David Haynes committed
59
        """
David Haynes's avatar
David Haynes committed
60
        String representation of this object.
David Haynes's avatar
David Haynes committed
61
        """
62
63
64
        return '<Registered User: %s - Approval Status: %s>' % (
            self.user, self.approved
        )
65
66
67

@receiver(post_save, sender=User)
def handle_regUser_creation(sender, instance, created, **kwargs):
David Haynes's avatar
David Haynes committed
68
    """
69
    When a post_save is called on a User object (and it is newly created), this
David Haynes's avatar
David Haynes committed
70
    is called to create an associated RegisteredUser.
David Haynes's avatar
David Haynes committed
71
    """
72
73
74
    if created:
        RegisteredUser.objects.create(user=instance)

75
class URL(models.Model):
David Haynes's avatar
David Haynes committed
76
    """
David Haynes's avatar
David Haynes committed
77
78
79
    This model represents a stored URL redirection rule. Each URL has an
    owner, target url, short identifier, click counter, and expiration
    date.
David Haynes's avatar
David Haynes committed
80
    """
81
    # Who is the owner of this Go link
David Haynes's avatar
David Haynes committed
82
    owner = models.ForeignKey(RegisteredUser, on_delete="cascade")
83
    # When was this link created?
David Haynes's avatar
David Haynes committed
84
    date_created = models.DateTimeField(default=timezone.now)
85

86
    # What is the target URL for this Go link
David Haynes's avatar
David Haynes committed
87
    target = models.URLField(max_length=1000)
88
    # What is the actual go link (short url) for this URL
David Haynes's avatar
David Haynes committed
89
    short = models.SlugField(max_length=20, primary_key=True)
90

91
    # how many people have visited this Go link
David Haynes's avatar
David Haynes committed
92
    clicks = models.IntegerField(default=0)
93
    # how many people have visited this Go link through the qr code
David Haynes's avatar
David Haynes committed
94
    qrclicks = models.IntegerField(default=0)
95
    # how many people have visited the go link through social media
David Haynes's avatar
David Haynes committed
96
    socialclicks = models.IntegerField(default=0)
97

98
    # does this Go link expire on a certain date
David Haynes's avatar
David Haynes committed
99
    expires = models.DateTimeField(blank=True, null=True)
100

101
    def __str__(self):
David Haynes's avatar
David Haynes committed
102
        """
David Haynes's avatar
David Haynes committed
103
        String representation of this object.
David Haynes's avatar
David Haynes committed
104
        """
105
106
107
        return '<Owner: %s - Target URL: %s>' % (
            self.owner.user, self.target
        )
108
109

    class Meta:
David Haynes's avatar
David Haynes committed
110
        """
David Haynes's avatar
David Haynes committed
111
        Meta information for this object.
David Haynes's avatar
David Haynes committed
112
        """
113
        # they should be ordered by their short links
114
115
116
117
        ordering = ['short']

    @staticmethod
    def generate_valid_short():
David Haynes's avatar
David Haynes committed
118
119
120
121
        """
        legacy method to ensure that generated short URL's are valid
        should be updated to be simpler
        """
122
        if cache.get("hashids_counter") is None:
123
124
125
126
            cache.set("hashids_counter", URL.objects.count())
        tries = 1
        while tries < 100:
            try:
Nicholas J Anderson's avatar
Nicholas J Anderson committed
127
                short = HASHIDS.encrypt(cache.get("hashids_counter"))
128
129
                tries += 1
                cache.incr("hashids_counter")
Nicholas J Anderson's avatar
Nicholas J Anderson committed
130
                URL.objects.get(short__iexact=short)
131
            except URL.DoesNotExist as ex:
132
                print(ex)
133
134
                return short
        return None