-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from Ayshyama/phil_set_up_postgresql_db
Set up postgresql db
- Loading branch information
Showing
10 changed files
with
373 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Generated by Django 4.2.5 on 2023-11-16 11:03 | ||
|
||
from django.conf import settings | ||
import django.contrib.auth.models | ||
import django.contrib.auth.validators | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
import django.utils.timezone | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
('app_exercises', '0001_initial'), | ||
('auth', '0012_alter_user_first_name_max_length'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='CustomUser', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('password', models.CharField(max_length=128, verbose_name='password')), | ||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), | ||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), | ||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), | ||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), | ||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), | ||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), | ||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), | ||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), | ||
('bio', models.TextField(blank=True, max_length=500)), | ||
('image', models.ImageField(blank=True, upload_to='images/')), | ||
('email', models.EmailField(max_length=254, unique=True)), | ||
('life', models.PositiveSmallIntegerField(default=10)), | ||
('day_streak', models.PositiveSmallIntegerField(default=0)), | ||
], | ||
options={ | ||
'verbose_name': 'user', | ||
'verbose_name_plural': 'users', | ||
'abstract': False, | ||
}, | ||
managers=[ | ||
('objects', django.contrib.auth.models.UserManager()), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='UserStatistic', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('date', models.DateTimeField(auto_now_add=True)), | ||
('progress', models.PositiveSmallIntegerField(default=0)), | ||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='UserProgress', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('date', models.DateTimeField(auto_now_add=True)), | ||
('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_exercises.exercise')), | ||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='UserExerciseConversation', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('message', models.TextField()), | ||
('is_human', models.BooleanField(default=False)), | ||
('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_exercises.exercise')), | ||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
migrations.AddField( | ||
model_name='customuser', | ||
name='exercises_done', | ||
field=models.ManyToManyField(through='app_accounts.UserProgress', to='app_exercises.exercise'), | ||
), | ||
migrations.AddField( | ||
model_name='customuser', | ||
name='groups', | ||
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups'), | ||
), | ||
migrations.AddField( | ||
model_name='customuser', | ||
name='user_permissions', | ||
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions'), | ||
), | ||
] |
23 changes: 23 additions & 0 deletions
23
app_accounts/migrations/0002_rename_date_userprogress_datetime_and_more.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Generated by Django 4.2.5 on 2023-11-16 15:30 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('app_accounts', '0001_initial'), | ||
] | ||
|
||
operations = [ | ||
migrations.RenameField( | ||
model_name='userprogress', | ||
old_name='date', | ||
new_name='datetime', | ||
), | ||
migrations.AlterField( | ||
model_name='userstatistic', | ||
name='date', | ||
field=models.DateField(auto_now_add=True), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,44 @@ | ||
from django.contrib.auth.models import AbstractUser | ||
from django.db import models | ||
from django.db.models.signals import m2m_changed | ||
from django.dispatch import receiver | ||
from app_exercises.models import Exercise | ||
|
||
# Create your models here. | ||
|
||
class CustomUser(AbstractUser): | ||
bio = models.TextField(max_length=500, blank=True) | ||
image = models.ImageField(upload_to='images/', blank=True) | ||
email = models.EmailField(unique=True) | ||
life = models.PositiveSmallIntegerField(default=10) | ||
exercises_done = models.ManyToManyField(Exercise, through='UserProgress') | ||
day_streak = models.PositiveSmallIntegerField(default=0) | ||
|
||
|
||
class UserExerciseConversation(models.Model): | ||
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE) | ||
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE) | ||
message = models.TextField() | ||
is_human = models.BooleanField(default=False) | ||
|
||
|
||
class UserProgress(models.Model): | ||
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE) | ||
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE) | ||
datetime = models.DateTimeField(auto_now_add=True) | ||
|
||
|
||
class UserStatistic(models.Model): | ||
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE) | ||
date = models.DateField(auto_now_add=True) | ||
progress = models.PositiveSmallIntegerField(default=0) | ||
|
||
|
||
@receiver(m2m_changed, sender=CustomUser.exercises_done.through) | ||
def create_user_progress(sender, instance, action, reverse, model, pk_set, **kwargs): | ||
if action == "post_add" and not reverse: | ||
for exercise_pk in pk_set: | ||
UserProgress.objects.create(user=instance, exercise_id=exercise_pk) | ||
|
||
|
||
# Connect the signal | ||
m2m_changed.connect(create_user_progress, sender=CustomUser.exercises_done.through) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
from django.test import TestCase | ||
|
||
# Create your tests here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Generated by Django 4.2.5 on 2023-11-16 11:03 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='Exercise', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.TextField()), | ||
('is_test', models.BooleanField(default=False)), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='Keywords', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('keyword', models.CharField(max_length=100)), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='Subject', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.CharField(max_length=100)), | ||
('description', models.TextField(blank=True, max_length=500)), | ||
('image', models.ImageField(upload_to='images/')), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='TestAnswer', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.CharField(max_length=500)), | ||
('is_correct', models.BooleanField(default=False)), | ||
('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_exercises.exercise')), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='Module', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.CharField(max_length=100)), | ||
('description', models.TextField(blank=True, max_length=500)), | ||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_exercises.subject')), | ||
], | ||
), | ||
migrations.CreateModel( | ||
name='Lesson', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.CharField(max_length=100)), | ||
('description', models.TextField(blank=True, max_length=500)), | ||
('module', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_exercises.module')), | ||
], | ||
), | ||
migrations.AddField( | ||
model_name='exercise', | ||
name='keywords', | ||
field=models.ManyToManyField(to='app_exercises.keywords'), | ||
), | ||
migrations.AddField( | ||
model_name='exercise', | ||
name='lesson', | ||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_exercises.lesson'), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,42 @@ | ||
from django.db import models | ||
|
||
# Create your models here. | ||
|
||
class Subject(models.Model): | ||
name = models.CharField(max_length=100) | ||
description = models.TextField(max_length=500, blank=True) | ||
image = models.ImageField(upload_to='images/') | ||
|
||
|
||
class Module(models.Model): | ||
name = models.CharField(max_length=100) | ||
description = models.TextField(max_length=500, blank=True) | ||
subject = models.ForeignKey(Subject, on_delete=models.CASCADE) | ||
|
||
|
||
class Lesson(models.Model): | ||
name = models.CharField(max_length=100) | ||
description = models.TextField(max_length=500, blank=True) | ||
module = models.ForeignKey(Module, on_delete=models.CASCADE) | ||
|
||
|
||
class Exercise(models.Model): | ||
name = models.TextField() | ||
lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE) | ||
keywords = models.ManyToManyField('Keywords') | ||
is_test = models.BooleanField(default=False) | ||
|
||
|
||
class Keywords(models.Model): | ||
keyword = models.CharField(max_length=100) | ||
|
||
|
||
class TestAnswer(models.Model): | ||
name = models.CharField(max_length=500) | ||
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE) | ||
is_correct = models.BooleanField(default=False) | ||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,88 @@ | ||
from django.test import TestCase | ||
from django.utils import timezone | ||
|
||
from app_accounts.models import CustomUser, UserExerciseConversation, UserStatistic, UserProgress | ||
from app_exercises.models import Subject, Module, Lesson, Exercise, Keywords, TestAnswer | ||
|
||
|
||
class ModelCreationTestCase(TestCase): | ||
|
||
lesson = None | ||
module = None | ||
subject = None | ||
keyword = None | ||
exercise = None | ||
user = None | ||
progress = None | ||
|
||
@classmethod | ||
def setUpTestData(cls): | ||
# Set up non-modified objects used by all test methods | ||
cls.subject = Subject.objects.create(name='Mathematics', description='Study of numbers') | ||
cls.module = Module.objects.create(name='Algebra', | ||
description='About algebra', | ||
subject=cls.subject) | ||
cls.lesson = Lesson.objects.create(name='Quadratic Equations', | ||
description='Introduction to Quadratic Equations', | ||
module=cls.module) | ||
cls.exercise = Exercise.objects.create(name='Solve Quadratic Equations x^2 - 5x + 6 = 0', | ||
lesson=cls.lesson, | ||
is_test=True) | ||
cls.keyword = Keywords.objects.create(keyword='quadratic') | ||
cls.exercise.keywords.add(cls.keyword) | ||
cls.test_answer = TestAnswer.objects.create(name='x=2 and x=3', | ||
exercise=cls.exercise, | ||
is_correct=True) | ||
|
||
cls.user = CustomUser.objects.create_user(username='john', email='[email protected]', password='123') | ||
cls.conversation = UserExerciseConversation.objects.create(user=cls.user, exercise=cls.exercise, | ||
message='Hello', is_human=True) | ||
|
||
cls.statistic = UserStatistic.objects.create(user=cls.user, progress=UserProgress.objects.count()) | ||
|
||
def test_subject_creation(self): | ||
self.assertEqual(self.subject.name, 'Mathematics') | ||
self.assertEqual(self.subject.description, 'Study of numbers') | ||
|
||
def test_module_creation(self): | ||
self.assertEqual(self.module.name, 'Algebra') | ||
self.assertEqual(self.module.subject, self.subject) | ||
|
||
def test_lesson_creation(self): | ||
self.assertEqual(self.lesson.name, 'Quadratic Equations') | ||
self.assertEqual(self.lesson.module, self.module) | ||
|
||
def test_exercise_creation(self): | ||
self.assertEqual(self.exercise.name, 'Solve Quadratic Equations x^2 - 5x + 6 = 0') | ||
self.assertEqual(self.exercise.lesson, self.lesson) | ||
self.assertTrue(self.exercise.is_test) | ||
|
||
def test_keywords_association(self): | ||
self.assertIn(self.keyword, self.exercise.keywords.all()) | ||
|
||
def test_test_answer_creation(self): | ||
self.assertEqual(self.test_answer.name, 'x=2 and x=3') | ||
self.assertEqual(self.test_answer.exercise, self.exercise) | ||
self.assertTrue(self.test_answer.is_correct) | ||
|
||
def test_custom_user_creation(self): | ||
self.assertEqual(self.user.username, 'john') | ||
self.assertEqual(self.user.email, '[email protected]') | ||
self.assertEqual(self.user.life, 10) | ||
self.assertEqual(self.user.day_streak, 0) | ||
|
||
def test_user_exercise_conversation_creation(self): | ||
self.assertEqual(self.conversation.user, self.user) | ||
self.assertEqual(self.conversation.exercise, self.exercise) | ||
self.assertEqual(self.conversation.message, 'Hello') | ||
self.assertTrue(self.conversation.is_human) | ||
|
||
def test_user_progress_auto_creation(self): | ||
# Assume user and exercise have been created in setUpTestData | ||
self.user.exercises_done.add(self.exercise) | ||
|
||
# Now check if a UserProgress instance was created | ||
progress_exists = UserProgress.objects.filter(user=self.user, exercise=self.exercise).exists() | ||
self.assertTrue(progress_exists, | ||
"UserProgress instance was not created when an exercise was added to exercises_done.") | ||
|
||
# Create your tests here. |
Binary file not shown.
Oops, something went wrong.