From 4803987bbbf2af5fcb8eccc4fb7cc427a4b754b0 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Fri, 25 Aug 2017 16:00:38 -0400 Subject: [PATCH 01/10] Added Show model --- LandingPage/models.py | 57 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 ++ 2 files changed, 59 insertions(+) create mode 100644 requirements.txt diff --git a/LandingPage/models.py b/LandingPage/models.py index 71a8362..14c9dbd 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -1,3 +1,60 @@ from django.db import models +from django.core.files.storage import FileSystemStorage +from django.conf import settings +import os + +def name_artwork(inst, name): + return '%s/artwork.%s'%(inst.abbr,name.split('.')[-1]) +def name_css(inst, name): + return '%s/style.css'%inst.abbr +def name_banner(inst, name): + return '%s/banner.%s'%(inst.abbr,name.split('.')[-1]) # Create your models here. +class Show(models.Model): + show_static_storage = FileSystemStorage(location=os.path.join(os.path.dirname(settings.MEDIA_ROOT), 'uploaded_resources'), base_url='showstatic') + name = models.CharField( + max_length=40, + help_text="The full name of the show", + verbose_name="Full Name" + ) + abbr = models.SlugField( + max_length=5, + unique=True, + help_text="A short abbreviation of the show, for use in urls", + verbose_name="Abbreviation" + ) + description = models.TextField( + help_text="A description of the show", + verbose_name="Description" + ) + release = models.DateField( + help_text="The release date of the first episode of the show", + verbose_name="Release Date" + ) + artwork = models.ImageField( + storage=show_static_storage, + upload_to = name_artwork, + help_text="The artwork associated with the show. Should display the name of the show in a movie-poster esque format. Aspect ration should be about 2:3", + verbose_name="Artwork" + ) + imdb = models.URLField( + help_text="The url of the IMDb page for this show", + verbose_name="IMDb Page" + ) + moderated = models.BooleanField( + help_text="Wheter or not this show is user-moderated", + verbose_name="User Moderated" + ) + css = models.FileField( + storage=show_static_storage, + upload_to=name_css, + help_text="The CSS stylesheet applied to this show's page", + verbose_name="Custom Style" + ) + banner = models.ImageField( + storage=show_static_storage, + upload_to = name_banner, + help_text="A banner used for the show's page.", + verbose_name="Artwork" + ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a3f04e5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Django==1.11.4 +Pillow=4.2.1 From 84bd805ea95029951067a8d4a067f3d9cce4e067 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Fri, 25 Aug 2017 19:23:53 -0400 Subject: [PATCH 02/10] Added the rest of the LandingPage models --- LandingPage/models.py | 115 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/LandingPage/models.py b/LandingPage/models.py index 14c9dbd..9585c41 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -58,3 +58,118 @@ class Show(models.Model): help_text="A banner used for the show's page.", verbose_name="Artwork" ) + +class User(models.Model): + auth_token=models.CharField( + max_length=16, + help_text="User's authentication token from IcyNet's auth system", + verbose_name="IcyNet Auth Token" + ) + display_name=models.CharField( + max_length=20, + help_text="The name shown to other users", + verbose_name="Display Name" + ) + +class Admin(User): + pass + +class Ban(models.Model): + user = models.OneToOneField( + User, + on_delete=models.CASCADE, + help_text="The user this ban applies to", + verbose_name="Banned User" + ) + admin = models.ForeignKey( + Admin, + on_delete=models.SET_NULL, + null=True, + help_text='The admin which banned this user', + verbose_name='Banned By', + related_name='bans' + ) + reason = models.CharField( + max_length=50, + blank=True, + help_text='The reason this user was banned', + verbose_name='Ban Reason' + ) + expiration = models.DateField( + help_text='The date this user will become unbanned', + blank=True, + verbose_name='Expiration Date' + ) + permanent = models.BooleanField( + help_text='If checked, this user will never be unbanned, even if the expiration date passes', + verbose_name='Permanent' + ) + scope = models.ManyToManyField( + Show, + help_text='The shows this user is banned from interacting with', + verbose_name='Banned From', + related_name='bans' + ) + site_wide = models.BooleanField( + help_text='If checked, this is a site-wide ban, and the user is automatically banned from all shows, not just those in the Banned From (scope) paramenter', + verbose_name = 'Site Wide Ban' + ) +class ShowModerator(models.Model): + show = models.ForeignKey( + Show, + on_delete=models.CASCADE, + help_text='The show this user moderates', + verbose_name='Moderated Show', + related_name='moderators', + ) + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + help_text='The user who moderates this show', + verbose_name='Moderator', + related_name='moderated_shows' + ) + appointed_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name='appointed_mods', + null=True, + help_text='The user who appointed this moderator', + verbose_name='Appointed by' + ) +class Report(models.Model): + reporter = models.ForeignKey( + User, + on_delete=models.SET_NULL, + null=True, + related_name='reports', + help_text='The user who created this report', + verbose_name='Reporter' + ) + title = models.CharField( + max_length=50, + help_text='A brief summary of the report', + verbose_name='Title' + ) + details = models.TextField( + help_text='The details of the report, preferably including why the content should be removed', + verbose_name = 'Details' + ) + url = models.URLField( + max_length=100, + help_text='The URL of the content being reported', + verbose_name = 'Content URL' + ) +class ShowSubmission(models.Model): + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + related_name='show_submissions', + help_text='The user who submitted this show', + verbose_name='Submitter' + ) + name = Show.name + details = models.TextField( + help_text='Some details about the show. Why it should be added, where information about it can be found, etc.', + verbose_name='Details' + ) From 234f163090f6309bd3f2cf090676a5db46e6f6c4 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Fri, 25 Aug 2017 19:37:45 -0400 Subject: [PATCH 03/10] Typo --- LandingPage/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index 9585c41..afc3fc2 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -43,7 +43,7 @@ class Show(models.Model): verbose_name="IMDb Page" ) moderated = models.BooleanField( - help_text="Wheter or not this show is user-moderated", + help_text="Whether or not this show is user-moderated", verbose_name="User Moderated" ) css = models.FileField( From 3cf80e1255b0f7b8b2a549e18757c1292a4597e2 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Fri, 25 Aug 2017 19:39:54 -0400 Subject: [PATCH 04/10] Registered models with the admin page --- LandingPage/admin.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/LandingPage/admin.py b/LandingPage/admin.py index 8c38f3f..75dc7b0 100644 --- a/LandingPage/admin.py +++ b/LandingPage/admin.py @@ -1,3 +1,11 @@ from django.contrib import admin +from .models import * # Register your models here. +admin.site.register(Show) +admin.site.register(User) +admin.site.register(Admin) +admin.site.register(Ban) +admin.site.register(ShowModerator) +admin.site.register(Report) +admin.site.register(ShowSubmission) From 7c8b06433c319ce3b22dea9cfc5b4b0a0befb2f8 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Sat, 26 Aug 2017 02:25:09 -0400 Subject: [PATCH 05/10] Added the rest of the tables --- LandingPage/models.py | 189 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index afc3fc2..7c906b4 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -9,10 +9,12 @@ def name_css(inst, name): return '%s/style.css'%inst.abbr def name_banner(inst, name): return '%s/banner.%s'%(inst.abbr,name.split('.')[-1]) +def name_season_artwork(inst, name): + return '%s/%d/artwork.%s'%(inst.show.abbr,inst.number,name.split('.')[-1]) +show_static_storage = FileSystemStorage(location=os.path.join(os.path.dirname(settings.MEDIA_ROOT), 'uploaded_resources'), base_url='showstatic') # Create your models here. class Show(models.Model): - show_static_storage = FileSystemStorage(location=os.path.join(os.path.dirname(settings.MEDIA_ROOT), 'uploaded_resources'), base_url='showstatic') name = models.CharField( max_length=40, help_text="The full name of the show", @@ -70,6 +72,15 @@ class User(models.Model): help_text="The name shown to other users", verbose_name="Display Name" ) + favorites=models.ManyToManyField( + 'Episode', + related_name='favorited_by', + through='Favorite' + ) + watches=models.ManyToManyField( + 'Episode', + related_name='watched_by', + through='Watch' class Admin(User): pass @@ -114,6 +125,7 @@ class Ban(models.Model): help_text='If checked, this is a site-wide ban, and the user is automatically banned from all shows, not just those in the Banned From (scope) paramenter', verbose_name = 'Site Wide Ban' ) + class ShowModerator(models.Model): show = models.ForeignKey( Show, @@ -137,6 +149,7 @@ class ShowModerator(models.Model): help_text='The user who appointed this moderator', verbose_name='Appointed by' ) + class Report(models.Model): reporter = models.ForeignKey( User, @@ -160,6 +173,7 @@ class Report(models.Model): help_text='The URL of the content being reported', verbose_name = 'Content URL' ) + class ShowSubmission(models.Model): user = models.ForeignKey( User, @@ -173,3 +187,176 @@ class ShowSubmission(models.Model): help_text='Some details about the show. Why it should be added, where information about it can be found, etc.', verbose_name='Details' ) + +# Create your models here. +class Season(models.Model): + show = models.ForeignKey( + 'Show', + on_delete=models.CASCADE, + related_name='seasons', + help_text='The show this season belongs to' + ) + name = models.CharField( + max_length=40, + blank=True, + help_text='The name given to this season by its producers. Can be blank if no name was given', + verbose_name='Season Name' + ) + number = models.IntegerField( + help_text='The number of this season, starting at 1; For example, the first season to be aired would be number 1, and the second would be number 2' + ) + description = models.TextField( + help_text='A description of this season\'s happenings' + ) + artwork = models.ImageField( + storage=show_static_storage, + upload_to = name_season_artwork, + help_text="The artwork associated with the season. Should display the name of the show in a movie-poster esque format. Aspect ration should be about 2:3", + verbose_name="Artwork", + blank=True + ) + +class Episode(models.Model): + show = models.ForeignKey( + 'Show', + on_delete=models.CASCADE, + related_name='episodes', + help_text='The show this episode belongs to' + ) + season = models.ForeignKey( + Season, + on_delete=models.CASCADE, + related_name='episodes', + help_text='The season this episode is from' + ) + episode = models.IntegerField( + help_text='The position of this episode in the season. The first episode of the season to air would be episode number 1', + verbose_name='Episode Number' + ) + name = models.CharField( + max_length=40, + help_text='The name given to this episode by its producers', + verbose_name='Episode Season' + ) + summary = models.TextField( + help_text='A summary of this episode' + ) + airdate = models.DateField( + help_text='The date this episode officially aired for the first time', + verbose_name='Original Air Date' + ) + +class Submission(models.Model): + episode = models.ForeignKey( + Episode, + on_delete=models.CASCADE, + related_name='submissions', + help_text='What episode this link contains a mirror of', + verbose_name='Submitted For' + ) + user = models.ForeignKey( + 'User', + on_delete=models.SET_NULL, + null=True, + related_name='submissions', + help_text='The user who submitted this link' + ) + url = models.URLField( + help_text='The link that was submitted', + ) + tags = models.CharField( + help_text='Tags applied to this link submission', + max_length=200 + ) + +class SubmissionVote(models.Model): + submission = models.ForeignKey( + Submission, + on_delete=models.CASCADE, + related_name='votes', + help_text='What this submission was cast on' + ) + user = models.ForeignKey( + 'User', + on_delete=models.CASCADE, + related_name='votes', + help_text='The user who cast this vote' + ) + positive = models.BooleanField( + help_text='If this is true, the vote is an upvote. Otherwise, it is a downvote' + ) + +class Favorite(models.Model): + user = models.ForeignKey( + User, + on_delete=models.CASCADE + ) + episode = models.ForeignKey( + Episode, + on_delete=models.CASCADE + ) + +class Watch(models.Model): + user = models.ForeignKey( + User, + on_delete=models.CASCADE + ) + episode = models.ForeignKey( + Episode, + on_delete=models.CASCADE + ) + +class DiscussionBoard(models.Model): + show = models.ForeignKey( + Show, + on_delete=models.CASCADE, + related_name='discussion_boards', + help_text='The show this discussion was created for' + ) + user = models.ForeignKey( + User, + on_delete=models.SET_NULL, + null=True, + related_name='discussion_boards', + help_text='The user that created this discussion' + ) + title = models.CharField( + max_length=100, + help_text='The title of the discussion' + ) + body = models.TextField( + help_text='The body of the post' + verbose_name='Body' + ) + +class DiscussionReply(models.Model): + board = models.ForeignKey( + DiscussionBoard, + on_delete=models.CASCADE, + related_name='replies', + help_text='The discussion board this was created in reply to' + ) + user = models.ForeignKey( + User, + on_delete=models.SET_NULL, + null=True, + related_name='replies', + help_text='The user that posted this reply' + ) + body = models.TextField( + help_text='The body of the response' + verbose_name='Body' + ) + +class DiscussionVote(models.Model): + user = models.ForeignKey( + User, + on_delete=models.CASCADE + ) + board = models.ForeignKey( + DiscussionBoard, + on_delete=models.CASCADE + ) + postive = models.BooleanField( + help_text='If true, the vote is an upvote. Otherwise, it is a downvote. Neutral votes are not recorded' + ) From f1a6760af77da3b296077e32518a549374965cf1 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Sat, 26 Aug 2017 02:29:42 -0400 Subject: [PATCH 06/10] Added more info to the DiscussionVote table --- LandingPage/models.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index 7c906b4..c373478 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -351,11 +351,15 @@ class DiscussionReply(models.Model): class DiscussionVote(models.Model): user = models.ForeignKey( User, - on_delete=models.CASCADE + on_delete=models.CASCADE, + related_name='discussion_votes', + help_text='The user which cast this vote' ) board = models.ForeignKey( DiscussionBoard, - on_delete=models.CASCADE + on_delete=models.CASCADE, + related_name='votes', + help_text='The board this vote was cast on' ) postive = models.BooleanField( help_text='If true, the vote is an upvote. Otherwise, it is a downvote. Neutral votes are not recorded' From 7e9fdbf3b7de38f3d9c5b9e1e56c566a21cb4413 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Sat, 26 Aug 2017 02:37:20 -0400 Subject: [PATCH 07/10] Added timestamps --- LandingPage/models.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index c373478..11f1875 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -14,7 +14,15 @@ def name_season_artwork(inst, name): show_static_storage = FileSystemStorage(location=os.path.join(os.path.dirname(settings.MEDIA_ROOT), 'uploaded_resources'), base_url='showstatic') # Create your models here. -class Show(models.Model): +class TimestampedModel: + timestamp = models.DateTimeField( + auto_now=True, + help_text='The date and time this object was created' + ) + class Meta: + abstract = True + +class Show(TimestampedModel): name = models.CharField( max_length=40, help_text="The full name of the show", @@ -61,7 +69,7 @@ class Show(models.Model): verbose_name="Artwork" ) -class User(models.Model): +class User(TimestampedModel): auth_token=models.CharField( max_length=16, help_text="User's authentication token from IcyNet's auth system", @@ -85,7 +93,7 @@ class User(models.Model): class Admin(User): pass -class Ban(models.Model): +class Ban(TimestampedModel): user = models.OneToOneField( User, on_delete=models.CASCADE, @@ -126,7 +134,7 @@ class Ban(models.Model): verbose_name = 'Site Wide Ban' ) -class ShowModerator(models.Model): +class ShowModerator(TimestampedModel): show = models.ForeignKey( Show, on_delete=models.CASCADE, @@ -150,7 +158,7 @@ class ShowModerator(models.Model): verbose_name='Appointed by' ) -class Report(models.Model): +class Report(TimestampedModel): reporter = models.ForeignKey( User, on_delete=models.SET_NULL, @@ -174,7 +182,7 @@ class Report(models.Model): verbose_name = 'Content URL' ) -class ShowSubmission(models.Model): +class ShowSubmission(TimestampedModel): user = models.ForeignKey( User, on_delete=models.CASCADE, @@ -246,7 +254,7 @@ class Episode(models.Model): verbose_name='Original Air Date' ) -class Submission(models.Model): +class Submission(TimestampedModel): episode = models.ForeignKey( Episode, on_delete=models.CASCADE, @@ -269,7 +277,7 @@ class Submission(models.Model): max_length=200 ) -class SubmissionVote(models.Model): +class SubmissionVote(TimestampedModel): submission = models.ForeignKey( Submission, on_delete=models.CASCADE, @@ -286,7 +294,7 @@ class SubmissionVote(models.Model): help_text='If this is true, the vote is an upvote. Otherwise, it is a downvote' ) -class Favorite(models.Model): +class Favorite(TimestampedModel): user = models.ForeignKey( User, on_delete=models.CASCADE @@ -296,7 +304,7 @@ class Favorite(models.Model): on_delete=models.CASCADE ) -class Watch(models.Model): +class Watch(TimestampedModel): user = models.ForeignKey( User, on_delete=models.CASCADE @@ -306,7 +314,7 @@ class Watch(models.Model): on_delete=models.CASCADE ) -class DiscussionBoard(models.Model): +class DiscussionBoard(TimestampedModel): show = models.ForeignKey( Show, on_delete=models.CASCADE, @@ -329,7 +337,7 @@ class DiscussionBoard(models.Model): verbose_name='Body' ) -class DiscussionReply(models.Model): +class DiscussionReply(TimestampedModel): board = models.ForeignKey( DiscussionBoard, on_delete=models.CASCADE, @@ -348,7 +356,7 @@ class DiscussionReply(models.Model): verbose_name='Body' ) -class DiscussionVote(models.Model): +class DiscussionVote(TimestampedModel): user = models.ForeignKey( User, on_delete=models.CASCADE, From c0bff596dbbb365b40d8fa1b1c70aeb068fc1f5f Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Sat, 26 Aug 2017 02:40:28 -0400 Subject: [PATCH 08/10] Cleaned up errors --- LandingPage/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index 11f1875..d5fcf6d 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -14,7 +14,7 @@ def name_season_artwork(inst, name): show_static_storage = FileSystemStorage(location=os.path.join(os.path.dirname(settings.MEDIA_ROOT), 'uploaded_resources'), base_url='showstatic') # Create your models here. -class TimestampedModel: +class TimestampedModel(models.Model): timestamp = models.DateTimeField( auto_now=True, help_text='The date and time this object was created' @@ -89,6 +89,7 @@ class User(TimestampedModel): 'Episode', related_name='watched_by', through='Watch' + ) class Admin(User): pass @@ -333,7 +334,7 @@ class DiscussionBoard(TimestampedModel): help_text='The title of the discussion' ) body = models.TextField( - help_text='The body of the post' + help_text='The body of the post', verbose_name='Body' ) @@ -352,7 +353,7 @@ class DiscussionReply(TimestampedModel): help_text='The user that posted this reply' ) body = models.TextField( - help_text='The body of the response' + help_text='The body of the response', verbose_name='Body' ) From 1f81e5a6f63188e7e57028039d19f70f5523b0ad Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Sat, 26 Aug 2017 15:01:56 -0400 Subject: [PATCH 09/10] Clean duplicate comment --- LandingPage/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index d5fcf6d..edb82be 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -197,7 +197,6 @@ class ShowSubmission(TimestampedModel): verbose_name='Details' ) -# Create your models here. class Season(models.Model): show = models.ForeignKey( 'Show', From a8fbd82b0a49aff9d86af81096f109049af67c9c Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Sat, 26 Aug 2017 15:08:14 -0400 Subject: [PATCH 10/10] Updated User model --- LandingPage/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/LandingPage/models.py b/LandingPage/models.py index edb82be..e36a055 100644 --- a/LandingPage/models.py +++ b/LandingPage/models.py @@ -70,10 +70,11 @@ class Show(TimestampedModel): ) class User(TimestampedModel): - auth_token=models.CharField( - max_length=16, - help_text="User's authentication token from IcyNet's auth system", - verbose_name="IcyNet Auth Token" + user_id = models.IntField( + help_text='The user id assigned to this user by IcyNet\'s auth servers' + ) + email = models.EmailField( + help_text='This user\'s email address' ) display_name=models.CharField( max_length=20,