From 88d3c22b1252d0641df0798776ab8b0613eb23e9 Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 15 Jan 2020 22:04:55 +0100 Subject: [PATCH 1/4] Added initial migration --- src/core/migrations/0001_initial.py | 109 ++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/core/migrations/0001_initial.py diff --git a/src/core/migrations/0001_initial.py b/src/core/migrations/0001_initial.py new file mode 100644 index 0000000..eebf6e9 --- /dev/null +++ b/src/core/migrations/0001_initial.py @@ -0,0 +1,109 @@ +# Generated by Django 3.0.2 on 2020-01-15 21:04 + +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='Badge', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=256, unique=True)), + ('desc', models.CharField(max_length=1000)), + ('icon', models.FileField(upload_to='badge_icons/')), + ('rarity', models.CharField(choices=[(1, 'Normal'), (2, 'Rare'), (3, 'Super Rare')], default=1, max_length=10)), + ], + ), + migrations.CreateModel( + name='Gamer', + fields=[ + ('steamid', models.IntegerField(primary_key=True, serialize=False, unique=True)), + ('communityvisibilitystate', models.BooleanField()), + ('profilestate', models.BooleanField()), + ('personaname', models.CharField(max_length=32)), + ('profileurl', models.URLField(max_length=256)), + ('avatar', models.URLField(max_length=256)), + ('commentpermission', models.BooleanField()), + ('timecreated', models.IntegerField(null=True)), + ('loccountrycode', models.CharField(max_length=2, null=True)), + ('API_KEY', models.CharField(max_length=32, null=True)), + ('badges', models.ManyToManyField(to='core.Badge')), + ], + ), + migrations.CreateModel( + name='ItemInstance', + fields=[ + ('instanceid', models.IntegerField(primary_key=True, serialize=False, unique=True)), + ('market_tradable_restriction', models.IntegerField()), + ('inspect_link', models.URLField(max_length=512, null=True)), + ('wear', models.CharField(max_length=100)), + ('float', models.FloatField()), + ('paintseed', models.IntegerField()), + ('killeatervalue', models.IntegerField(null=True)), + ('customname', models.CharField(max_length=128, null=True)), + ], + ), + migrations.CreateModel( + name='ItemType', + fields=[ + ('paint_index', models.IntegerField(primary_key=True, serialize=False, unique=True)), + ('classid', models.IntegerField()), + ('appid', models.IntegerField()), + ('tradable', models.BooleanField(default=False)), + ('icon_url', models.URLField(max_length=512, null=True)), + ('name', models.CharField(max_length=1000)), + ('name_color', models.CharField(max_length=7)), + ('type', models.CharField(max_length=1000)), + ('rarity', models.CharField(max_length=1000)), + ('min_float', models.FloatField()), + ('max_float', models.FloatField()), + ], + ), + migrations.CreateModel( + name='Stickers', + fields=[ + ('stickerid', models.IntegerField(primary_key=True, serialize=False, unique=True)), + ('name', models.CharField(max_length=1000)), + ], + ), + migrations.CreateModel( + name='Offer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('items_give', models.ManyToManyField(related_name='OfferedItems', to='core.ItemInstance')), + ('items_want', models.ManyToManyField(related_name='WantedItems', to='core.ItemInstance')), + ('offeror', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Gamer')), + ], + ), + migrations.AddField( + model_name='iteminstance', + name='item_class', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='core.ItemType'), + ), + migrations.AddField( + model_name='iteminstance', + name='stickers', + field=models.ManyToManyField(to='core.Stickers'), + ), + migrations.AddField( + model_name='gamer', + name='inventory', + field=models.ManyToManyField(to='core.ItemInstance'), + ), + migrations.AddField( + model_name='gamer', + name='system_user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] From ff713e37c887df68f53c381a26cc543808b8384e Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 15 Jan 2020 23:06:52 +0100 Subject: [PATCH 2/4] Added Config Draft --- src/common/templates/master.html | 2 +- src/core/templates/core/signup.html | 1 + src/core/urls.py | 4 +++- src/core/views.py | 13 +++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/core/templates/core/signup.html diff --git a/src/common/templates/master.html b/src/common/templates/master.html index e6706e1..0125f90 100644 --- a/src/common/templates/master.html +++ b/src/common/templates/master.html @@ -24,7 +24,7 @@ {% if user.is_authenticated %} Add Offer | settings | Welcome, {{ user.gamer.display_name }} {% else %} - + {% endif %} diff --git a/src/core/templates/core/signup.html b/src/core/templates/core/signup.html new file mode 100644 index 0000000..d4b29a2 --- /dev/null +++ b/src/core/templates/core/signup.html @@ -0,0 +1 @@ +{{ url }} diff --git a/src/core/urls.py b/src/core/urls.py index f7f277c..b87cb78 100644 --- a/src/core/urls.py +++ b/src/core/urls.py @@ -16,5 +16,7 @@ urlpatterns = [ path('help', views.help, name='help'), path('imprint', views.imprint, name='imprint'), - path('about', views.about, name='about') + path('about', views.about, name='about'), + + path('signup', views.signup, name='signup') ] diff --git a/src/core/views.py b/src/core/views.py index edefb96..68a7ce1 100644 --- a/src/core/views.py +++ b/src/core/views.py @@ -2,6 +2,8 @@ from .models import Offer, Gamer from django.shortcuts import render, get_object_or_404, redirect from django.http import HttpResponseForbidden from django.contrib.auth.decorators import login_required +# For Steam Open ID handling +from oic.oic import Client # STATIC PAGES @@ -36,6 +38,17 @@ def search(request, filter): return render(request, 'core/filter.html') +# USER SIGNUP +def signup(request): + client = Client() + issuer = client.discover('https://steamcommunity.com/openid/login') + #provider_info = client.provider_config(issuer) + context = { + 'url': issuer + } + return render(request, 'core/signup.html', context) + + # USER AREA @login_required def offer_refresh(request, offerID): From dddbb1c340cbc1dc25ed373a187e816384c62c3e Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 16 Jan 2020 14:46:22 +0100 Subject: [PATCH 3/4] Added Float Retrival Function --- src/core/models.py | 12 ++++++++++++ src/core/steam_api.py | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/src/core/models.py b/src/core/models.py index ac907eb..111e3c4 100644 --- a/src/core/models.py +++ b/src/core/models.py @@ -52,6 +52,18 @@ class ItemInstance(models.Model): customname = models.CharField(max_length=128, null=True) # Nametag stickers = models.ManyToManyField(Stickers) + def getInspectLink(self): + if self.getOwner(): + fresh_link = self.inspect_link + link = fresh_link.replace("%owner_steamid%", self.getOwner().steamid).replace("%assetid%", self.instanceid) + return link + return False + + def getOwner(self): + if Gamer.objects.filter(inventory__contains=self).exists(): + return Gamer.objects.filter(inventory__contains=self)[0] + return False + # Badges that can be eared on the site class Badge(models.Model): diff --git a/src/core/steam_api.py b/src/core/steam_api.py index c8158f7..419832d 100644 --- a/src/core/steam_api.py +++ b/src/core/steam_api.py @@ -8,6 +8,8 @@ STEAM_SERVER = 'https://api.steampowered.com/' USER_METHOD = 'ISteamUser/GetPlayerSummaries/v2' INVENTORY_SERVER = 'https://steamcommunity.com/inventory/' +FLOAT_SERVER = 'https://api.csgofloat.com/?url=' + # Get the mandatory gamer info for a gamer def getUserInfo(steamID, API_KEY=settings.STEAM_API_KEY): @@ -21,3 +23,8 @@ def getUserInventory(steamID, API_KEY=settings.STEAM_API_KEY, GAME_ID=730): QUERY = INVENTORY_SERVER + '/' + steamID + '/' + GAME_ID + '/2?l=english&count=5000' inventory_object = json.load(urllib.request.urlopen(QUERY)) return inventory_object + + +def getFloat(asset, steamID): + QUERY = FLOAT_SERVER + asset.getInspectLink() + return json.load(urllib.request.urlopen(QUERY)) From c10f542ceeb6ae58d7795f500c6e9fe593c17499 Mon Sep 17 00:00:00 2001 From: Conrad Date: Sun, 19 Jan 2020 00:05:51 +0100 Subject: [PATCH 4/4] Added OpenID Support --- src/core/admin.py | 5 ++++ src/core/models.py | 3 +- src/core/urls.py | 3 +- src/core/views.py | 75 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/src/core/admin.py b/src/core/admin.py index 9c242e0..c60a927 100644 --- a/src/core/admin.py +++ b/src/core/admin.py @@ -7,3 +7,8 @@ from .models import ItemType, Stickers, ItemInstance, Badge, Gamer class ItemTypeAdmin(admin.ModelAdmin): list_display = ('paint_index', 'name', 'type', 'rarity', 'min_float', 'max_float', 'tradable') list_editable = () + + +@admin.register(Gamer) +class Gamer(admin.ModelAdmin): + list_display = ('steamid', 'communityvisibilitystate', 'profilestate', 'personaname', 'commentpermission', 'timecreated', 'loccountrycode') diff --git a/src/core/models.py b/src/core/models.py index 111e3c4..3315964 100644 --- a/src/core/models.py +++ b/src/core/models.py @@ -107,4 +107,5 @@ class Offer(models.Model): @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): - instance.gamer.save() + if Gamer.objects.filter(system_user=instance).exists(): + instance.gamer.save() diff --git a/src/core/urls.py b/src/core/urls.py index b87cb78..51cb86e 100644 --- a/src/core/urls.py +++ b/src/core/urls.py @@ -18,5 +18,6 @@ urlpatterns = [ path('imprint', views.imprint, name='imprint'), path('about', views.about, name='about'), - path('signup', views.signup, name='signup') + path('signup', views.signup, name='signup'), + path('signup_confirm', views.signup_confirm) ] diff --git a/src/core/views.py b/src/core/views.py index 68a7ce1..801f3cc 100644 --- a/src/core/views.py +++ b/src/core/views.py @@ -1,9 +1,35 @@ +# Import the local models from .models import Offer, Gamer +# Django shortcuts for certain things from django.shortcuts import render, get_object_or_404, redirect +# For catching permission errors from django.http import HttpResponseForbidden +# For permitting only logged in users to see their private area from django.contrib.auth.decorators import login_required # For Steam Open ID handling -from oic.oic import Client +from urllib import parse +# For requesting the identification check +import requests +# For manually creating system users +from django.contrib.auth.models import User +# For getting the API interaction methods +from .steam_api import getUserInfo +# Import for manually logging in user after creation +from django.contrib.auth import login + + +# HELPER +def validate_steam_login(params): + steam_login_url_base = "https://steamcommunity.com/openid/login" + + new_params = params.copy() + new_params["openid.mode"] = "check_authentication" + + r = requests.post(steam_login_url_base, data=new_params) + + if "is_valid:true" in r.text: + return True + return False # STATIC PAGES @@ -40,13 +66,44 @@ def search(request, filter): # USER SIGNUP def signup(request): - client = Client() - issuer = client.discover('https://steamcommunity.com/openid/login') - #provider_info = client.provider_config(issuer) - context = { - 'url': issuer + steam_openid_url = 'https://steamcommunity.com/openid/login' + u = { + 'openid.ns': "http://specs.openid.net/auth/2.0", + 'openid.identity': "http://specs.openid.net/auth/2.0/identifier_select", + 'openid.claimed_id': "http://specs.openid.net/auth/2.0/identifier_select", + 'openid.mode': 'checkid_setup', + 'openid.return_to': 'http://' + request.META['HTTP_HOST'] + '/signup_confirm', + 'openid.realm': 'http://' + request.META['HTTP_HOST'] + '' } - return render(request, 'core/signup.html', context) + + query_string = parse.urlencode(u) + auth_url = steam_openid_url + '?' + query_string + return redirect(auth_url) + + +def signup_confirm(request): + if validate_steam_login(request.GET): + claimed_id = request.GET.get('openid.claimed_id') + claimed_id = claimed_id.split('/')[-1] + new_user, created = User.objects.get_or_create(username=claimed_id) + + if created: + info = getUserInfo(claimed_id) + Gamer.objects.create( + steamid=claimed_id, + system_user=new_user, + communityvisibilitystate=(True if info['response']['players'][0]['communityvisibilitystate'] == 3 else False), + profilestate=info['response']['players'][0]['profilestate'], + personaname=info['response']['players'][0]['personaname'], + profileurl=info['response']['players'][0]['profileurl'], + avatar=info['response']['players'][0]['avatar'], + commentpermission=info['response']['players'][0]['commentpermission'], + timecreated=info['response']['players'][0]['timecreated'] or None, + loccountrycode=info['response']['players'][0]['loccountrycode'] or None + ) + login(request, new_user) + return redirect(me) + return HttpResponseForbidden() # USER AREA @@ -81,10 +138,10 @@ def profile(request, steamID): # PRIVATE AREA @login_required def me(request): - return render(request, 'core/profile.html', {'gamer': Gamer.object.get(system_user=request.User)}) + return render(request, 'core/profile.html', {'gamer': Gamer.objects.get(system_user=request.user)}) @login_required def me_settings(request): - dude = get_object_or_404(Gamer, system_user=request.User) + dude = get_object_or_404(Gamer, system_user=request.user) return render(request, 'core/settings.html', {'gamer': dude})