diff --git a/.vscode/settings.json b/.vscode/settings.json index a954313..fd2fbf2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,8 @@ { "python.linting.pylintArgs": [ "--load-plugins=pylint_django", - "--django-settings-module=.settings", + "--django-settings-module=levelup.settings", ], - "python.pythonPath": "/Users/jason.ross/.local/share/virtualenvs/levelup-server-Wy00p224/bin/python", "python.linting.pylintEnabled": true, "python.linting.enabled": true } diff --git a/levelup/urls.py b/levelup/urls.py index 6414569..01c8ce8 100644 --- a/levelup/urls.py +++ b/levelup/urls.py @@ -14,8 +14,12 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin +from django.conf.urls import include from django.urls import path +from levelupapi.views import register_user, login_user urlpatterns = [ + path('register', register_user), + path('login', login_user), path('admin/', admin.site.urls), -] +] \ No newline at end of file diff --git a/levelupapi/db.sql b/levelupapi/db.sql new file mode 100644 index 0000000..aca671e --- /dev/null +++ b/levelupapi/db.sql @@ -0,0 +1,4 @@ + +SELECT * FROM auth_user; +SELECT * FROM authtoken_token; +SELECT * FROM levelupapi_gamer; \ No newline at end of file diff --git a/levelupapi/fixtures/events.json b/levelupapi/fixtures/events.json new file mode 100644 index 0000000..2558f1e --- /dev/null +++ b/levelupapi/fixtures/events.json @@ -0,0 +1,24 @@ +[ + { + "model":"levelupapi.event", + "pk": 1, + "fields":{ + "game": 1, + "description": "Dungeons and Dragons session 0, ", + "date": "2022-02-15", + "time": "19:00", + "organizer": 1 + } + }, + { + "model":"levelupapi.event", + "pk": 2, + "fields":{ + "game": 2, + "description": "Raid on the Lich King, final Alliance campaign raid", + "date": "2022-02-22", + "time": "12:00", + "organizer": 1 + } + } +] \ No newline at end of file diff --git a/levelupapi/fixtures/game_types.json b/levelupapi/fixtures/game_types.json new file mode 100644 index 0000000..b7e94ce --- /dev/null +++ b/levelupapi/fixtures/game_types.json @@ -0,0 +1,23 @@ +[ + { + "model": "levelupapi.gametype", + "pk": 1, + "fields": { + "label": "Board game" + } + }, + { + "model": "levelupapi.gametype", + "pk": 2, + "fields": { + "label": "Role-playing game" + } + }, + { + "model": "levelupapi.gametype", + "pk": 3, + "fields": { + "label": "MMO game" + } + } +] \ No newline at end of file diff --git a/levelupapi/fixtures/gamers.json b/levelupapi/fixtures/gamers.json new file mode 100644 index 0000000..2fe32f0 --- /dev/null +++ b/levelupapi/fixtures/gamers.json @@ -0,0 +1,10 @@ +[ + { + "model": "levelupapi.gamer", + "pk": 1, + "fields": { + "user": 1, + "bio": "Me" + } + } +] \ No newline at end of file diff --git a/levelupapi/fixtures/games.json b/levelupapi/fixtures/games.json new file mode 100644 index 0000000..fc99187 --- /dev/null +++ b/levelupapi/fixtures/games.json @@ -0,0 +1,27 @@ +[ + { + "model": "levelupapi.game", + "pk":1, + "fields": { + "game_type": 2, + "title": "Dungeons & Dragons, 5th edition", + "maker": "Wizards of the Coast", + "gamer" : 1, + "number_of_players": 4, + "skill_level": 6 + } + }, + { + "model": "levelupapi.game", + "pk": 2, + "fields": { + "game_type": 2, + "title": "World of Warcraft", + "maker": "Blizzard/Activision", + "gamer" : 1, + "number_of_players": 10000, + "skill_level": 4 + } + } + +] \ No newline at end of file diff --git a/levelupapi/fixtures/tokens.json b/levelupapi/fixtures/tokens.json new file mode 100644 index 0000000..1f3e0a4 --- /dev/null +++ b/levelupapi/fixtures/tokens.json @@ -0,0 +1,10 @@ +[ + { + "model": "authtoken.token", + "pk": "fa2eba9be8282d595c997ee5cd49f2ed31f65bed", + "fields": { + "user": 1, + "created": "2020-08-29T13:24:27.172Z" + } + } +] \ No newline at end of file diff --git a/levelupapi/fixtures/users.json b/levelupapi/fixtures/users.json new file mode 100644 index 0000000..198f256 --- /dev/null +++ b/levelupapi/fixtures/users.json @@ -0,0 +1,20 @@ +[ + { + "model": "auth.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$216000$qMRH8szID7Z8$Vljya2V3XfruOHuvx1hGz9ZyKg4bxbw7rc2WO0gTR7I=", + "last_login": null, + "is_superuser": false, + "username": "Carrie1945", + "first_name": "Carrie", + "last_name": "Belk", + "email": "me@me.com", + "is_staff": false, + "is_active": true, + "date_joined": "2020-08-28T14:51:39.989Z", + "groups": [], + "user_permissions": [] + } + } +] \ No newline at end of file diff --git a/levelupapi/migrations/0001_initial.py b/levelupapi/migrations/0001_initial.py new file mode 100644 index 0000000..41638d6 --- /dev/null +++ b/levelupapi/migrations/0001_initial.py @@ -0,0 +1,71 @@ +# Generated by Django 4.0.1 on 2022-02-07 16:48 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.CharField(max_length=256)), + ('date', models.DateField()), + ('time', models.TimeField(verbose_name='')), + ], + ), + migrations.CreateModel( + name='GameType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.CharField(max_length=50)), + ], + ), + migrations.CreateModel( + name='Gamer', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.CharField(max_length=50)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Game', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=256)), + ('maker', models.CharField(max_length=256)), + ('number_of_players', models.IntegerField()), + ('skill_level', models.IntegerField()), + ('game_type', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='levelupapi.gametype')), + ('gamer', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='levelupapi.gamer')), + ], + ), + migrations.CreateModel( + name='EventGamer', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='levelupapi.event')), + ('gamer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='levelupapi.gamer')), + ], + ), + migrations.AddField( + model_name='event', + name='game', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='levelupapi.game'), + ), + migrations.AddField( + model_name='event', + name='organizer', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='levelupapi.gamer'), + ), + ] diff --git a/levelupapi/models/__init__.py b/levelupapi/models/__init__.py index 0f5fc57..a02c0c3 100644 --- a/levelupapi/models/__init__.py +++ b/levelupapi/models/__init__.py @@ -1 +1,5 @@ -from .gamer import Gamer \ No newline at end of file +from levelupapi.models.gamer import Gamer +from levelupapi.models.events import Event +from levelupapi.models.game import Game +from levelupapi.models.game_type import GameType +from levelupapi.models.event_gamer import EventGamer \ No newline at end of file diff --git a/levelupapi/models/event_gamer.py b/levelupapi/models/event_gamer.py new file mode 100644 index 0000000..9d71141 --- /dev/null +++ b/levelupapi/models/event_gamer.py @@ -0,0 +1,9 @@ +from django.db import models +from levelupapi.models.gamer import Gamer +from levelupapi.models.events import Event +class EventGamer(models.Model): + + #Event won't change color for some reason. Reference this if something breaks later + gamer= models.ForeignKey("Gamer", on_delete=models.CASCADE) + event = models.ForeignKey("Event", on_delete=models.CASCADE) + \ No newline at end of file diff --git a/levelupapi/models/events.py b/levelupapi/models/events.py index 2276f9c..6ce28a1 100644 --- a/levelupapi/models/events.py +++ b/levelupapi/models/events.py @@ -1,12 +1,11 @@ from django.db import models from levelupapi.models.gamer import Gamer -from models import Game +from levelupapi.models.game import Game +class Event(models.Model): -class Game(models.Model): - - game= models.ForeignKey(Game) + game= models.ForeignKey(Game, on_delete=models.DO_NOTHING) description = models.CharField(max_length=256) date = models.DateField() - time = models.TimeField(_(""), auto_now=False, auto_now_add=False) - organizer = models.ForeignKey(Gamer) \ No newline at end of file + time = models.TimeField((""), auto_now=False, auto_now_add=False) + organizer = models.ForeignKey(Gamer, on_delete=models.DO_NOTHING) \ No newline at end of file diff --git a/levelupapi/models/game.py b/levelupapi/models/game.py index 627a1f9..a4b7c86 100644 --- a/levelupapi/models/game.py +++ b/levelupapi/models/game.py @@ -1,12 +1,13 @@ from django.db import models -from models import Gamer +from levelupapi.models.game_type import GameType +from levelupapi.models.gamer import Gamer class Game(models.Model): - game_type = models.ForeignKey(game_type) + game_type = models.ForeignKey(GameType, on_delete=models.DO_NOTHING) title = models.CharField(max_length=256) maker = models.CharField(max_length=256) - gamer = models.ForeignKey(Gamer) - number_of_players = models.IntegerField(max_value = 1, max_value = 128) - skill_level = models.IntegerField(max_value = 1, max_value = 100) \ No newline at end of file + gamer = models.ForeignKey(Gamer, on_delete=models.DO_NOTHING) + number_of_players = models.IntegerField() + skill_level = models.IntegerField() \ No newline at end of file diff --git a/levelupapi/models/game_type.py b/levelupapi/models/game_type.py new file mode 100644 index 0000000..92e61d3 --- /dev/null +++ b/levelupapi/models/game_type.py @@ -0,0 +1,6 @@ +from django.db import models + + +class GameType(models.Model): + + label= models.CharField(max_length=50) \ No newline at end of file diff --git a/levelupapi/views/__init__.py b/levelupapi/views/__init__.py index e69de29..0801135 100644 --- a/levelupapi/views/__init__.py +++ b/levelupapi/views/__init__.py @@ -0,0 +1 @@ +from .auth import login_user, register_user \ No newline at end of file diff --git a/levelupapi/views/auth.py b/levelupapi/views/auth.py new file mode 100644 index 0000000..b69ffc5 --- /dev/null +++ b/levelupapi/views/auth.py @@ -0,0 +1,66 @@ +from django.contrib.auth import authenticate +from django.contrib.auth.models import User +from rest_framework.authtoken.models import Token +from rest_framework.decorators import api_view, permission_classes +from rest_framework.permissions import AllowAny +from rest_framework.response import Response + +from levelupapi.models import Gamer + +@api_view(['POST']) +@permission_classes([AllowAny]) +def login_user(request): + '''Handles the authentication of a gamer + + Method arguments: + request -- The full HTTP request object + ''' + username = request.data['username'] + password = request.data['password'] + + # Use the built-in authenticate method to verify + # authenticate returns the user object or None if no user is found + authenticated_user = authenticate(username=username, password=password) + + # If authentication was successful, respond with their token + if authenticated_user is not None: + token = Token.objects.get(user=authenticated_user) + data = { + 'valid': True, + 'token': token.key + } + return Response(data) + else: + # Bad login details were provided. So we can't log the user in. + data = { 'valid': False } + return Response(data) + +@api_view(['POST']) +@permission_classes([AllowAny]) +def register_user(request): + '''Handles the creation of a new gamer for authentication + + Method arguments: + request -- The full HTTP request object + ''' + + # Create a new user by invoking the `create_user` helper method + # on Django's built-in User model + new_user = User.objects.create_user( + username=request.data['username'], + password=request.data['password'], + first_name=request.data['first_name'], + last_name=request.data['last_name'] + ) + + # Now save the extra info in the levelupapi_gamer table + gamer = Gamer.objects.create( + bio=request.data['bio'], + user=new_user + ) + + # Use the REST Framework's token generator on the new user account + token = Token.objects.create(user=gamer.user) + # Return the token to the client + data = { 'token': token.key } + return Response(data)