Here it is! Beta 1.0 source code!
This commit is contained in:
parent
1ef3a33763
commit
a4a52b233b
46 changed files with 1413 additions and 0 deletions
0
api/__init__.py
Normal file
0
api/__init__.py
Normal file
3
api/admin.py
Normal file
3
api/admin.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
api/apps.py
Normal file
6
api/apps.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'api'
|
||||
0
api/migrations/__init__.py
Normal file
0
api/migrations/__init__.py
Normal file
3
api/models.py
Normal file
3
api/models.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
api/tests.py
Normal file
3
api/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
37
api/urls.py
Normal file
37
api/urls.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('service_hosts', views.service_hosts, name='servicehosts'),
|
||||
path('country/<str:country>', views.country, name='country'),
|
||||
path('my/session/!open', views.open, name='opensession'),
|
||||
path('my/session/!open_without_nna', views.open, name='opensession_withoutnna'),
|
||||
path('my/session/!close', views.close, name="endsession"),
|
||||
path('my/balance/current', views.balance, name="balance"),
|
||||
path('my/wishlist/notice', views.dummy_wishlist, name="wishlist"),
|
||||
path('my/wishlist/!put', views.put_wishlist, name="wishlist"),
|
||||
path('my/wishlist/<int:tid>/!delete', views.delete_wishlist, name="wishlist"),
|
||||
path('my/wishlist', views.wishlist, name='mywishlist'),
|
||||
path('my/shared_titles', views.shared_titles, name='shared_titles'),
|
||||
path('my/owned_coupons', views.owned_coupons, name="ownedcoupons"),
|
||||
path('my/shared_title_ids', views.ownedtitles, name="sharedtitleids"),
|
||||
path('my/language', views.language, name='language'),
|
||||
path('my/account/ctr/!migrate_without_nna', views.empty, name="migrate"),
|
||||
path('my/npns_status', views.empty, name="npns_status"),
|
||||
path('my/parental_control/!put', views.empty, name="parental_control"),
|
||||
path('<str:country>/titles/online_prices', views.online_price, name="online_prices"),
|
||||
path('<str:country>/title/<int:tid>/ec_info', views.ec_info, name="ecinfo"),
|
||||
path('<str:country>/title/<int:tid>/prepurchase_info', views.prepurchase_info, name="prepurchase"),
|
||||
path('<str:country>/title/<int:tid>/!purchase', views.purcahse_title, name="purchase"),
|
||||
path('<str:country>/title/<int:tid>/!redeem', views.redeem_title, name="redeemtitle"),
|
||||
path('<str:country>/title/public_status', views.public_status, name="publicstatus"),
|
||||
path('redeemable_card/!check', views.check_redeemable, name="checkredeem"),
|
||||
path('my/balance/prereplenish_info', views.pretransac_redeem, name="testredeem"),
|
||||
path('my/balance/current/!add_prepaid', views.add_money_prepaid, name="prepaid"),
|
||||
path('my/tax_location', views.tax_location, name="taxloc"),
|
||||
path('my/transactions', views.transactions, name="transactions"),
|
||||
path('my/votes', views.votes, name="votes"),
|
||||
path('my/votable_titles/!put', views.votable_titles, name="votable_titles"),
|
||||
path('titles/id_pair', views.id_pair, name="id_pair"),
|
||||
]
|
||||
341
api/views.py
Normal file
341
api/views.py
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
#CRAPPY CODE WARNING(!)
|
||||
from django.shortcuts import render
|
||||
from django.http import JsonResponse, HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from shopdeck import settings
|
||||
from shopdeckdb.models import *
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
import time, random, string
|
||||
|
||||
def id_generator(size=32, chars=string.ascii_uppercase + string.digits):
|
||||
return ''.join(random.choice(chars) for _ in range(size))
|
||||
|
||||
@csrf_exempt
|
||||
def service_hosts(request):
|
||||
res = {"services":{"service":[{"name":"CCIF","origin_fqdn":settings.SOAP_URL},{"name":"SAMURAI_CTR","origin_fqdn":settings.METADATA_API_URL,"cdn_fqdn":settings.METADATA_API_URL},{"name":"EOU","origin_fqdn":settings.SOAP_URL,"cdn_fqdn":settings.SOAP_URL}]}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def country(request, country):
|
||||
res = {"country_detail":{"region_code":"LOL","max_cash":{"amount":"99999,00 Credit","currency":"CREDIT","raw_value":"99999"},"loyalty_system_available":False,"legal_payment_message_required":False,"legal_business_message_required":False,"tax_excluded_country":False,"tax_free_country":False,"prepaid_card_available":True,"credit_card_available":False,"credit_card_store_available":False,"jcb_security_code_available":False,"nfc_available":False,"coupon_available":False,"my_coupon_available":True,"price_format":{"positive_prefix":"","positive_suffix":" Credit","negative_prefix":"- ","negative_suffix":" Credit","formats":{"format":[{"value":"# ### ### ###,##","digit":"#"}],"pattern_id":"5"}},"default_timezone":"+00:00","eshop_available":True,"name":country,"iso_code":country,"default_language_code":"en","language_selectable":False}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def open(request):
|
||||
data = request.POST
|
||||
if data.get("device_id")==None:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=data.get("device_id"))
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": True})
|
||||
if ds.is_terminated:
|
||||
return JsonResponse({"error": {"code": "8008", "message": "Your account has been terminated. Sorry."}}, status=400)
|
||||
request.session['deviceid'] = data.get("device_id")
|
||||
currenttime = int(round(time.time()*1000))
|
||||
id = id_generator()
|
||||
res = {"session_config":{"country":ds.country,"saved_lang":ds.language,"shop_account_initialized":False,"device_link_updated":False,"owned_titles_modified":currenttime,"shared_titles_last_modified":currenttime,"server_time":currenttime,"devices":{"device":[{"name":"CTR","id":4}]},"auto_billing_contracted":False,"id":id}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def close(request):
|
||||
request.session.flush()
|
||||
return HttpResponse()
|
||||
|
||||
@csrf_exempt
|
||||
def balance(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"balance":{"amount":str(ds.balance)+",00 Credit","currency":"EUR","raw_value":str(ds.balance)}}
|
||||
return JsonResponse(res)
|
||||
|
||||
#This is due to how eShop servers handle my/wishlist/notice: its a empty json, even if you have wishlisted titles
|
||||
@csrf_exempt
|
||||
def dummy_wishlist(request):
|
||||
res = {"wishlist_notice":{"wished_title_id":[],"total":0}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def wishlist(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
wishlisted_titles = wishlistedTitle.objects.filter(owner=ds)
|
||||
wishlisted = []
|
||||
for title in wishlisted_titles:
|
||||
wishlisted.append({"platform": {"name": title.title.platform.name, "id": title.title.platform.id, "device": "CTR", "category": title.title.genre.id}, "publisher": {"name": title.title.publisher.publisher_name, "id": title.title.publisher.id}, "display_genre": title.title.genre.name, "release_date_on_eshop": str(title.title.date), "release_date_on_original": str(title.title.date), "retail_sales": False, "eshop_sales": True, "in_app_purchase": title.title.in_app_purchase, "name": title.title.name, "id": title.title.id, "icon_url": title.title.icon_url, "banner_url": title.title.banner_url})
|
||||
res = {"wishlist":{"wished_title":wishlisted,"total":len(wishlisted)}}
|
||||
return JsonResponse(res)
|
||||
|
||||
#FIXME: Make this not just a static JSON response.
|
||||
@csrf_exempt
|
||||
def owned_coupons(request):
|
||||
res = {"coupons":{}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def ownedtitles(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
owned_titles = ownedTitle.objects.filter(owner=ds)
|
||||
owned = []
|
||||
i = 0
|
||||
for title in owned_titles:
|
||||
owned.append({"title_id": title.title.tid, "id": title.title.id, "index": i})
|
||||
i+1
|
||||
|
||||
res = {"owned_titles":{"owned_title":owned}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def language(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"session_config":{"saved_lang":ds.language}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def empty(request):
|
||||
return JsonResponse({})
|
||||
|
||||
@csrf_exempt
|
||||
def online_price(request, country):
|
||||
if request.GET.get('title[]') == None:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
tlist = list(request.GET.get('title[]').split(","))
|
||||
titles = []
|
||||
for ind_title in tlist:
|
||||
try:
|
||||
title = Title.objects.get(id=int(ind_title))
|
||||
try:
|
||||
titleowned = ownedTitle.objects.get(title=title, owner=ds)
|
||||
is_title_owned = True
|
||||
except ObjectDoesNotExist:
|
||||
is_title_owned = False
|
||||
if title.price == 0:
|
||||
titleprice = "Free"
|
||||
else:
|
||||
titleprice = str(title.price)+" Credit"
|
||||
titles.append({"title_id": int(ind_title), "eshop_sales_status": "onsale", "price": {"regular_price": {"amount": titleprice, "currency": "CREDIT", "raw_value": str(title.price), "id": 2172116800}}, "title_owned": is_title_owned})
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"online_prices": {"online_price": titles}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def ec_info(request, country, tid):
|
||||
try:
|
||||
title = Title.objects.get(id=tid)
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"title_ec_info":{"title_id":title.tid,"content_size":title.size,"title_version":title.version,"disable_download":title.is_not_downloadable}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def put_wishlist(request):
|
||||
try:
|
||||
title = Title.objects.get(id=int(request.POST.get("id")))
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
wishlisted = wishlistedTitle.objects.get(title=title, owner=ds)
|
||||
return JsonResponse({"error": True})
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
wishlisted = wishlistedTitle.objects.create(title=title, owner=ds)
|
||||
wishlisted.save()
|
||||
return JsonResponse({})
|
||||
|
||||
@csrf_exempt
|
||||
def delete_wishlist(request, tid):
|
||||
try:
|
||||
title = Title.objects.get(id=int(tid))
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
wishlisted = wishlistedTitle.objects.get(title=title, owner=ds)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": True})
|
||||
wishlisted.delete()
|
||||
return JsonResponse({})
|
||||
|
||||
@csrf_exempt
|
||||
def check_redeemable(request):
|
||||
try:
|
||||
card = redeemableCard.objects.get(code=request.POST.get("card_number"))
|
||||
except:
|
||||
return JsonResponse({"error": {"code": "6561", "message": "This code is incorrect.\nPlease check up your code and try again."}}, status=400)
|
||||
if card.used:
|
||||
return JsonResponse({"error": {"code": "3101", "message": "This code is already used.\nSorry!"}}, status=400)
|
||||
if card.is_money:
|
||||
res = {"redeemable_card": {"number": request.POST.get("card_number"),"cash": {"amount": card.content+" Credit","currency": "CREDIT","raw_value": card.content}}}
|
||||
return JsonResponse(res)
|
||||
else:
|
||||
try:
|
||||
title = Title.objects.get(tid=card.content)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": {"code": "5615", "message": "The corresponding title was not found.\nContact an administrator."}})
|
||||
if request.POST.get("tin") != None:
|
||||
return JsonResponse({"error": {"code": "6969", "message": "This is a title download code.\nPlease use the right tool."}})
|
||||
res = {"redeemable_card": {"number": request.POST.get("card_number"), "contents": {"content": [{"title": {"name": title.name, "id": title.id}}]},"title_ec_info": {"title_id": title.tid, "content_size": title.size, "title_version": title.version}}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def pretransac_redeem(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"prereplenish_info": {"current_balance": {"amount": str(ds.balance)+" Credit", "currency": "CREDIT", "raw_value": str(ds.balance)},"replenish_amount": {"amount": str(request.GET.get("replenish_amount"))+" Credit", "currency": "CREDIT", "raw_value": str(request.GET.get("replenish_amount"))},"post_balance": {"amount": str(int(float(request.GET.get("replenish_amount")))+ds.balance)+" Credit", "currency": "CREDIT", "raw_value": str(int(float(request.GET.get("replenish_amount")))+ds.balance)}}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def add_money_prepaid(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
card = redeemableCard.objects.get(code=request.POST.get("card_number"))
|
||||
except:
|
||||
return JsonResponse({"error": {"code": "6561", "message": "This code is incorrect.\nPlease check up your code and try again."}})
|
||||
if card.used:
|
||||
res = {"error": {"code": "4626", "message": "This code is already used.\nSorry!"}}
|
||||
res = {"transaction_result": {"transaction_id": 1,"post_balance": {"amount": str(int(card.content)+ds.balance)+" Credit","currency": "CREDIT","raw_value": str(int(card.content)+ds.balance)},"integrated_account": True}}
|
||||
card.used = True
|
||||
card.save()
|
||||
ds.balance = int(card.content)+ds.balance
|
||||
ds.save()
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def prepurchase_info(request, country, tid):
|
||||
try:
|
||||
title = Title.objects.get(id=int(tid))
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"prepurchase_info":{"tax_excluded":False,"purchasing_content":[{"eshop_sales_status":"onsale","content_size":title.size,"payment_amount":{"price":{"regular_price":{"amount":str(title.price)+",00 Credit","currency":"CREDIT","raw_value":str(title.price),"id":2172116800}},"total_amount":{"amount":str(title.price)+",00 Credit","currency":"CREDIT","raw_value":str(title.price)}}}],"current_balance":{"amount":str(ds.balance)+",00 Credit","currency":"CREDIT","raw_value":str(ds.balance)},"post_balance":{"amount":str(ds.balance-title.price)+",00 Credit","currency":"EUR","raw_value":str(ds.balance-title.price)},"total_amount":{"price":{"regular_price":{"amount":str(title.price)+",00 Credit","currency":"CREDIT","raw_value":str(title.price)}},"total_amount":{"amount":str(title.price)+",00 Credit","currency":"CREDIT","raw_value":str(title.price)}}}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def purcahse_title(request, country, tid):
|
||||
try:
|
||||
title = Title.objects.get(id=int(tid))
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
if not title.public:
|
||||
return JsonResponse({"error": {"code": "6265", "message": "This title is not public.\nYou cannot download it."}}, status=400)
|
||||
if ds.balance - title.price < 0:
|
||||
return JsonResponse({"error": {"code": "8167", "message": "You don't have enough money for that."}})
|
||||
try:
|
||||
owned = ownedTitle.objects.get(title=title, owner=ds)
|
||||
except ObjectDoesNotExist:
|
||||
ds.balance = ds.balance - title.price
|
||||
ds.save()
|
||||
owned = ownedTitle.objects.create(title=title, owner=ds)
|
||||
owned.save()
|
||||
res = {"transaction_result":{"transaction_id":1,"title_id":title.tid,"ticket_id":int(title.ticket_id),"post_balance":{"amount":str(ds.balance)+",00 Credit","currency":"CREDIT","raw_value":str(ds.balance)},"business_type":"NCL_DIST","integrated_account":True}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def tax_location(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"tax_location": {"state": "uwuland", "state_code": ds.country, "id": 71647}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def redeem_title(request, country, tid):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
title = Title.objects.get(id=int(tid))
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
card = redeemableCard.objects.get(code=request.POST.get("card_number"))
|
||||
except:
|
||||
return JsonResponse({"error": {"code": "6561", "message": "This code is incorrect.\nPlease check up your code and try again."}})
|
||||
if card.content != title.tid:
|
||||
return JsonResponse({"error": {"code": "9468", "message": "Invalid title ID.\nPlease check up your code and try again."}}, status=400)
|
||||
card.used = True
|
||||
card.save()
|
||||
owned = ownedTitle.objects.create(title=title, owner=ds)
|
||||
owned.save()
|
||||
res = {"transaction_result":{"transaction_id":1,"title_id":title.tid,"ticket_id":int(title.ticket_id),"post_balance":{"amount":str(ds.balance)+",00 Credit","currency":"CREDIT","raw_value":str(ds.balance)},"business_type":"NCL_DIST","integrated_account":True}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def transactions(request):
|
||||
return JsonResponse({"error": {"code": "8458", "message": "Useless shit.\nWe will never implement that.\nSorry."}}, status=400)
|
||||
|
||||
@csrf_exempt
|
||||
def shared_titles(request):
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.session["deviceid"])
|
||||
except:
|
||||
return JsonResponse({"error": True})
|
||||
ownedtitles = ownedTitle.objects.filter(owner=ds)
|
||||
wishlisted = []
|
||||
for title in ownedtitles:
|
||||
wishlisted.append({"platform": {"name": title.title.platform.name, "id": title.title.platform.id, "device": "CTR", "category": title.title.genre.id}, "publisher": {"name": title.title.publisher.publisher_name, "id": title.title.publisher.id}, "display_genre": title.title.genre.name, "release_date_on_eshop": str(title.title.date), "release_date_on_original": str(title.title.date), "retail_sales": False, "eshop_sales": True, "in_app_purchase": title.title.in_app_purchase, "name": title.title.name, "id": title.title.id, "icon_url": title.title.icon_url, "banner_url": title.title.banner_url})
|
||||
res = {"owned_titles":{"owned_title":wishlisted,"total":len(wishlisted)}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def id_pair(request):
|
||||
return JsonResponse({"error": {"code": "6569", "message": "Due to technical limitations,\nthis functionnality is not available."}}, status=401)
|
||||
|
||||
@csrf_exempt
|
||||
def public_status(request, country):
|
||||
if request.GET.get("ns_uid") == None:
|
||||
return JsonResponse({"error": True})
|
||||
try:
|
||||
title = Title.objects.get(id=int(request.GET.get("ns_uid")))
|
||||
except:
|
||||
return JsonResponse({"error": {"code": "5546", "message": "Title not found."}}, status=400)
|
||||
if title.public:
|
||||
type = "PUBLIC"
|
||||
else:
|
||||
type = "PRIVATE"
|
||||
res = {"title_public_status":{"public_status":type,"type":"T","ns_uid":title.id,"title_id":title.tid}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def votable_titles(request):
|
||||
return JsonResponse({"error": {"code": "5626", "message": "WIP. Not ready yet."}}, status=400)
|
||||
|
||||
@csrf_exempt
|
||||
def votes(request):
|
||||
return JsonResponse({"error": {"code": "5626", "message": "WIP. Not ready yet."}}, status=400)
|
||||
27
cas.py
Normal file
27
cas.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from flask import Blueprint, request, render_template, make_response
|
||||
import xmltodict, time, os
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
from shopdeckdb.models import *
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
cas = Blueprint("cas", "cas")
|
||||
@cas.route("/cas/services/CatalogingSOAP", methods=['POST'])
|
||||
def soap():
|
||||
if request.get_data() == b"IwI":
|
||||
return "TwT"
|
||||
try:
|
||||
parsed = xmltodict.parse(request.get_data())
|
||||
except:
|
||||
return "Error"
|
||||
if request.headers.get('User-Agent') != "CTR EC 040600 Mar 14 2012 13:32:39":
|
||||
return "Error"
|
||||
if "cas:ListTitlesEx" in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
try:
|
||||
title = Title.objects.get(tid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['cas:ListTitlesEx']['cas:TitleId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
r = make_response(render_template("cas/listTitlesEx.xml", id=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['cas:ListTitlesEx']['cas:DeviceId'], message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['cas:ListTitlesEx']['cas:MessageId'],time=int(round(time.time()*1000)), t=title))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
40
cdn.py
Normal file
40
cdn.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
from flask import Blueprint, make_response, request
|
||||
import os
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
from shopdeckdb.models import *
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
import os.path
|
||||
|
||||
ccs = Blueprint("ccs", "ccs")
|
||||
@ccs.route("/ccs/download/<tid>/tmd.<version>", methods=['GET'])
|
||||
def download_tmd(tid, version):
|
||||
try:
|
||||
title = Title.objects.get(tid=str(tid))
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=request.args.get('deviceId'))
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
try:
|
||||
owned = ownedTitle.objects.get(title=title, owner=ds)
|
||||
except ObjectDoesNotExist:
|
||||
return "error"
|
||||
path = str(os.path.dirname(__file__))+"/cdn/"+str(tid)+"/tmd.bin"
|
||||
if not os.path.isfile(path):
|
||||
return "error"
|
||||
f = open(path, mode="rb")
|
||||
r = make_response(f.read())
|
||||
r.headers.set("Content-Type", "application/octet-stream")
|
||||
return r
|
||||
@ccs.route("/ccs/download/<tid>/<app>", methods=['GET'])
|
||||
def download_app(tid, app):
|
||||
path = str(os.path.dirname(__file__))+"/cdn/"+str(tid)+"/"+str(app)+".app"
|
||||
if not os.path.isfile(path):
|
||||
return "error"
|
||||
f = open(path, mode="rb")
|
||||
r = make_response(f.read())
|
||||
r.headers.set("Content-Type", "application/octet-stream")
|
||||
return r
|
||||
1
cdn/README
Normal file
1
cdn/README
Normal file
|
|
@ -0,0 +1 @@
|
|||
Put the following files from a CIA file in a new folder with its title id: tmd.bin & the .app file (all uppercase)
|
||||
48
cia-helper.py
Normal file
48
cia-helper.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/python3
|
||||
# By Let's Shop team
|
||||
# Tool to parse cias easily
|
||||
# Heavily inspired by one of the examples
|
||||
# Created with help from ZeroSkill
|
||||
|
||||
from pyctr.type.cia import CIAReader, CIASection, InvalidCIAError
|
||||
from pyctr.crypto.engine import BootromNotFoundError
|
||||
import sys, base64
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
exit('Usage: ./cia-helper.py [cia file]')
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
with CIAReader(sys.argv[1]) as cia:
|
||||
print("Welcome to CIA Helper! This tool is designed to help you adding a homebrew to Let's Shop.")
|
||||
print("If the title needs to be downloaded with a redeemable card, please make the id like: 50000000000000")
|
||||
print("For the ticket id, put anything you want (in numbers), but be sure it starts by: 12")
|
||||
print('Title ID:', cia.tmd.title_id.upper())
|
||||
print('Title Version:',cia.tmd.title_version.__index__())
|
||||
app = cia.contents[CIASection.Application]
|
||||
app_title = app.exefs.icon.get_app_title('English')
|
||||
print('Application Title:', app_title.short_desc)
|
||||
print('Application Description:', app_title.long_desc)
|
||||
print('Application Publisher:', app_title.publisher)
|
||||
print('Product code:', app.product_code)
|
||||
print('Size:', cia.total_size)
|
||||
chunks = [ chunk for chunk in cia.tmd.chunk_records if chunk.cindex in cia.contents ]
|
||||
filename = chunks[0].id.upper()
|
||||
with open(filename+".app", 'wb') as file:
|
||||
file.write(cia.open_raw_section(CIASection.Application).read())
|
||||
with open("tmd.bin", 'wb') as file:
|
||||
file.write(cia.open_raw_section(CIASection.TitleMetadata).read())
|
||||
with open("ticket.txt", 'wb') as file:
|
||||
file.write(base64.b64encode(cia.open_raw_section(CIASection.Ticket).read()))
|
||||
print('Finished! You can now put the tmd.bin and the .app file in cdn/'+cia.tmd.title_id.upper()+' (create the folder)')
|
||||
print('Your base64-encoded ticket is available in ticket.txt.')
|
||||
print('Have a great day!')
|
||||
except BootromNotFoundError:
|
||||
print("Necessary files were not found. Please create a '3ds' directory in your home folder and put boot9.bin in it.")
|
||||
except FileNotFoundError:
|
||||
print("Your file does not exists.")
|
||||
except InvalidCIAError:
|
||||
print("Your file is not a CIA.")
|
||||
except:
|
||||
print("Something wrong happened. Sorry! (try again)")
|
||||
81
ecs.py
Normal file
81
ecs.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
from flask import Blueprint, request, render_template, make_response
|
||||
import xmltodict, os, random, string, time
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
from shopdeckdb.models import *
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from shopdeck import settings
|
||||
|
||||
#generate totally-genuine-devicetoken
|
||||
def id_generator(size=21, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
|
||||
return ''.join(random.choice(chars) for _ in range(size))
|
||||
|
||||
ecs = Blueprint("ecs", "ecs")
|
||||
@ecs.route("/ecs/services/ECommerceSOAP", methods=['POST'])
|
||||
def soap():
|
||||
if request.get_data() == b"OwO":
|
||||
return "UwU"
|
||||
try:
|
||||
parsed = xmltodict.parse(request.get_data())
|
||||
except:
|
||||
return "Error"
|
||||
if request.headers.get('User-Agent') != "CTR EC 040600 Mar 14 2012 13:32:39":
|
||||
return "Error"
|
||||
if 'ecs:GetAccountStatus' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
print("Some 3DS wants to connect")
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=str(parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:DeviceId']))
|
||||
except ObjectDoesNotExist:
|
||||
#Create new Client3DS object, and save it!
|
||||
print("New 3DSClient: "+str(parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:DeviceId']))
|
||||
ds = Client3DS.objects.create(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:DeviceId'], devicetoken=id_generator(), is_terminated=False, balance=0, language=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:Language'], region=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:Region'], country=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:Country'])
|
||||
if 'ecs:DeviceToken' not in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']:
|
||||
r = make_response(render_template("ecs/getAccountStatusError.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:MessageId'], time=int(round(time.time()*1000)), accountid=ds.id, country=ds.country, region=ds.region, setting=settings))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
try:
|
||||
ctid = customTitleID.objects.filter(related_to=ds)
|
||||
except ObjectDoesNotExist:
|
||||
ctid = []
|
||||
r = make_response(render_template("ecs/getAccountStatus.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:GetAccountStatus']['ecs:MessageId'], time=int(round(time.time()*1000)), accountid=ds.id, balance=ds.balance, country=ds.country, region=ds.region, customtid=ctid, setting=settings))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
if 'ecs:AccountListETicketIds' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:AccountListETicketIds']['ecs:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
try:
|
||||
ctid = customTitleID.objects.filter(related_to=ds)
|
||||
except ObjectDoesNotExist:
|
||||
ctid = []
|
||||
r = make_response(render_template("ecs/accountListETicketIds.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:AccountListETicketIds']['ecs:MessageId'],time=int(round(time.time()*1000)), customtid=ctid))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
if 'ecs:DeleteSavedCard' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
print("Synchronizing")
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:DeleteSavedCard']['ecs:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
r = make_response(render_template("ecs/deleteSavedCard.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:DeleteSavedCard']['ecs:MessageId'],time=int(round(time.time()*1000))))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
if 'ecs:AccountGetETickets' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
print("Sending ticket...")
|
||||
try:
|
||||
title = Title.objects.get(ticket_id=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:AccountGetETickets']['ecs:TicketId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:AccountGetETickets']['ecs:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
try:
|
||||
owned = ownedTitle.objects.get(title=title, owner=ds)
|
||||
except ObjectDoesNotExist:
|
||||
return "error"
|
||||
r = make_response(render_template("ecs/getAccountETickets.xml", id=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:AccountGetETickets']['ecs:DeviceId'], message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ecs:AccountGetETickets']['ecs:MessageId'],time=int(round(time.time()*1000)), t=title))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
57
ias.py
Normal file
57
ias.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
from flask import Blueprint, request, render_template, make_response
|
||||
import xmltodict, time, os
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
from shopdeckdb.models import *
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
ias = Blueprint("ias", "ias")
|
||||
@ias.route("/ias/services/IdentityAuthenticationSOAP", methods=['POST'])
|
||||
def soap():
|
||||
if request.get_data() == b"UwU":
|
||||
return "OwO"
|
||||
try:
|
||||
parsed = xmltodict.parse(request.get_data())
|
||||
except:
|
||||
return "Error"
|
||||
if request.headers.get('User-Agent') != "CTR EC 040600 Mar 14 2012 13:32:39":
|
||||
return "Error"
|
||||
if 'ias:SetIVSData' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:SetIVSData']['ias:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
r = make_response(render_template("ias/setIVSData.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:SetIVSData']['ias:MessageId'],time=int(round(time.time()*1000))))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
if 'ias:GetChallenge' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:GetChallenge']['ias:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
r = make_response(render_template("ias/getChallenge.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:GetChallenge']['ias:MessageId'],time=int(round(time.time()*1000))))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
if 'ias:Register' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
if str(parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Register']['ias:Challenge']) != '526726942':
|
||||
print(parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Register']['ias:Challenge'])
|
||||
return "Error"
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Register']['ias:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
r = make_response(render_template("ias/register.xml", id=ds.consoleid, message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Register']['ias:MessageId'],time=int(round(time.time()*1000)), accountid=ds.id, devicetoken=ds.devicetoken, country=ds.country))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
if 'ias:Unregister' in parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']:
|
||||
try:
|
||||
ds = Client3DS.objects.get(consoleid=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Unregister']['ias:DeviceId'])
|
||||
except ObjectDoesNotExist:
|
||||
return "Error"
|
||||
if int(parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Unregister']['ias:AccountId']) != int(ds.id):
|
||||
return "Error"
|
||||
ds.delete()
|
||||
r = make_response(render_template("ias/unregister.xml", id=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Unregister']['ias:DeviceId'], message=parsed['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ias:Unregister']['ias:MessageId'],time=int(round(time.time()*1000))))
|
||||
r.headers.set("Content-Type", "text/xml; charset=utf-8")
|
||||
return r
|
||||
12
main.py
Normal file
12
main.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
'''
|
||||
SOAP Server
|
||||
Made by Let's Shop! 2023
|
||||
'''
|
||||
from flask import Flask
|
||||
import ecs, ias, cas, cdn
|
||||
|
||||
app = Flask(__name__)
|
||||
app.register_blueprint(ecs.ecs)
|
||||
app.register_blueprint(ias.ias)
|
||||
app.register_blueprint(cas.cas)
|
||||
app.register_blueprint(cdn.ccs)
|
||||
25
manage.py
Normal file
25
manage.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python
|
||||
'''
|
||||
API & Metadata server
|
||||
Made by Let's Shop! 2023
|
||||
'''
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
0
metadata/__init__.py
Normal file
0
metadata/__init__.py
Normal file
3
metadata/admin.py
Normal file
3
metadata/admin.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
metadata/apps.py
Normal file
6
metadata/apps.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MetadataConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'metadata'
|
||||
0
metadata/migrations/__init__.py
Normal file
0
metadata/migrations/__init__.py
Normal file
3
metadata/models.py
Normal file
3
metadata/models.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
metadata/tests.py
Normal file
3
metadata/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
22
metadata/urls.py
Normal file
22
metadata/urls.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('news', views.news, name='news'),
|
||||
path('telops', views.telops, name="telops"),
|
||||
path('languages', views.language, name="language"),
|
||||
path('eshop_message/about', views.eshop_message, name="about"),
|
||||
path('eshop_message/agreement_send_info', views.agreement_send_info, name="agreementuseless"),
|
||||
path('directories', views.directories, name="directories"),
|
||||
path('directory/<int:cid>', views.directory, name="categoryview"),
|
||||
path('title/<int:tid>', views.title, name="titleview"),
|
||||
path('movie/<int:mid>', views.viewmovie, name="movie"),
|
||||
path('searchcategory', views.searchcategory, name="searchcategory"),
|
||||
path('genres', views.genres, name="genres"),
|
||||
path('publishers', views.publishers, name="publishers"),
|
||||
path('contents', views.contents, name="contents"),
|
||||
path('titles', views.titles, name="titles"),
|
||||
path('movies', views.movies_content, name="movies"),
|
||||
path('rankings', views.rankings, name="rankings")
|
||||
]
|
||||
331
metadata/views.py
Normal file
331
metadata/views.py
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
from django.shortcuts import render
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from shopdeck import settings
|
||||
from shopdeckdb.models import *
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from urllib.parse import unquote
|
||||
from dateutil import relativedelta
|
||||
import datetime
|
||||
@csrf_exempt
|
||||
def news(request, region):
|
||||
news = announcement.objects.all().order_by("-date")
|
||||
allnews = []
|
||||
for ann in news:
|
||||
ann.content = ann.content.replace("\\n", "\n")
|
||||
result = {"headline": ann.title, "description": ann.content, "date":int(ann.date.timestamp())}
|
||||
if ann.is_banner:
|
||||
result.update(images={"image":[{"index": 1, "type": "banner", "url": ann.banner_url, "height": 126, "width": 300}]})
|
||||
result.update(id=ann.id)
|
||||
allnews.append(result)
|
||||
res = {"news": {"news_entry": allnews, "length": len(allnews)}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def telops(request, region):
|
||||
motds = motd.objects.all().order_by('order')
|
||||
allmotds = []
|
||||
for ann in motds:
|
||||
allmotds.append(ann.content)
|
||||
res = {"telops": {"telop": allmotds, "length": len(allmotds)}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def language(request, region):
|
||||
lang = request.GET.get('lang', None)
|
||||
if lang == None:
|
||||
return JsonResponse({"error": True})
|
||||
res = {"languages":{"language":[{"iso_code":lang,"name":"Unknown"}]}}
|
||||
return JsonResponse(res)
|
||||
|
||||
#this should be named just tos but nintendo named it eshop message idfk why
|
||||
@csrf_exempt
|
||||
def eshop_message(request, region):
|
||||
res = {"text": {"type": "html", "body": settings.TOS_ESHOP}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def directories(request, region):
|
||||
dirs = category.objects.all().order_by('order')
|
||||
alldirectories = []
|
||||
for directory in dirs:
|
||||
alldirectories.append({"name": directory.name, "icon_url": directory.icon_url, "icon_width": 128, "icon_height": 96, "banner_url": directory.banner_url, "index": directory.index, "id": directory.id, "type": "search", "standard": directory.standard, "new": directory.new})
|
||||
res = {"directories": {"directory": alldirectories, "length": len(alldirectories), "catalog_id": 1}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def directory(request, region, cid):
|
||||
try:
|
||||
dir = category.objects.get(id=cid)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": True})
|
||||
if request.GET.get("platform[]") == None and request.GET.get("genre[]") == None and request.GET.get("publisher[]") == None and request.GET.get("price_max")==None and request.GET.get("price_min")==None:
|
||||
titles = Title.objects.filter(category=dir, public=True).order_by('-date')[int(request.GET.get("offset")):25+25]
|
||||
total = titles.count()
|
||||
movies = movie.objects.filter(category=dir).order_by('-date')
|
||||
total_movie = movies.count()
|
||||
total = total+total_movie
|
||||
else:
|
||||
#over complicated but at least works
|
||||
if request.GET.get("platform[]") == None:
|
||||
platforms = []
|
||||
all_platforms = platform.objects.all()
|
||||
for aplatform in all_platforms:
|
||||
platforms.append(aplatform.id)
|
||||
else:
|
||||
platforms = request.GET.get("platform[]").split(",")
|
||||
if request.GET.get("genre[]") == None:
|
||||
genrel = []
|
||||
all_genre = genre.objects.all()
|
||||
for agenre in all_genre:
|
||||
genrel.append(agenre.id)
|
||||
else:
|
||||
genrel = request.GET.get("genre[]").split(",")
|
||||
if request.GET.get("publisher[]") == None:
|
||||
publisherl = []
|
||||
all_publisher = publisher.objects.all()
|
||||
for apublisher in all_publisher:
|
||||
publisherl.append(apublisher.id)
|
||||
else:
|
||||
publisherl = request.GET.get("publisher[]").split(",")
|
||||
if request.GET.get("price_max") != None and request.GET.get("price_min") == None:
|
||||
titles = Title.objects.filter(price__lte=int(request.GET.get("price_max")),category=dir, platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_min") != None and request.GET.get("price_max") == None:
|
||||
titles = Title.objects.filter(price__gte=int(request.GET.get("price_min")),category=dir, platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_min") != None and request.GET.get("price_max") == None:
|
||||
titles = Title.objects.filter(price__gte=int(request.GET.get("price_min")),price__lte=int(request.GET.get("price_max")),category=dir, platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_max") == None and request.GET.get("price_min")==None:
|
||||
titles = Title.objects.filter(category=dir, platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
total = titles.count()
|
||||
alltitles = []
|
||||
i = 0
|
||||
for title in titles:
|
||||
if title.is_not_downloadable:
|
||||
is_downloadable = False
|
||||
else:
|
||||
is_downloadable = True
|
||||
alltitles.append({"title": {"platform": {"name": title.platform.name, "id": title.platform.id, "device": "CTR", "category": title.genre.id}, "publisher": {"name": title.publisher.publisher_name, "id": title.publisher.id}, "display_genre": title.genre.name, "release_date_on_eshop": str(title.date), "retail_sales": False, "eshop_sales": is_downloadable, "demo_available": False, "aoc_available": False, "in_app_purchase": title.in_app_purchase, "release_date_on_original": str(title.date), "name": title.name, "id": title.id, "product_code": title.product_code, "icon_url": title.icon_url, "banner_url": title.banner_url, "new": title.new}, "index": i})
|
||||
i = i + 1
|
||||
try:
|
||||
for Movie in movies:
|
||||
if i > 25:
|
||||
continue
|
||||
if Movie.is_3d:
|
||||
dimension = "3d"
|
||||
else:
|
||||
dimension = "2d"
|
||||
alltitles.append({"movie": {"name": Movie.name, "banner_url": Movie.banner_url, "thumbnail_url": Movie.thumbnail_url, "files": {"file": [{"format": "moflex", "movie_url": Movie.moflex_url, "width": 400, "height": 200, "dimension": dimension, "play_time_sec": Movie.time_in_sec}]}, "id": Movie.id, "new": Movie.new}, "index": i})
|
||||
i = i + 1
|
||||
except:
|
||||
pass
|
||||
res = {"directory": {"name": dir.name, "icon_url": dir.icon_url, "icon_width": 128, "icon_height": 96, "banner_url": dir.banner_url, "contents": {"content": alltitles, "length": len(alltitles), "offset": int(request.GET.get("offset")), "total": total}, "id": dir.id, "type": "search", "component": "title"}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def title(request, region, tid):
|
||||
try:
|
||||
title = Title.objects.get(id=tid)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": True})
|
||||
title.desc = title.desc.replace("\\n", "\n")
|
||||
if title.is_not_downloadable:
|
||||
is_downloadable = False
|
||||
else:
|
||||
is_downloadable = True
|
||||
res = {"title": {"formal_name": title.name, "description": title.desc, "genres": {"genre": [{"name": title.genre.name, "id": title.genre.id}], "length": 1}, "keywords": {}, "ticket_available": title.ticket_available, "title_size": title.size, "download_code_sales": False, "download_card_sales": {"available": False}, "name": title.name, "thumbnails": {"thumbnail": [{"url": title.thumbnail_url, "height": 112, "width": 112, "type": "small"}]}, "id": title.id, "platform": {"name": title.platform.name, "id": title.platform.id, "device": "CTR", "category": title.genre.id }, "publisher": {"name": title.publisher.publisher_name, "id": title.publisher.id}, "product_code": title.product_code, "icon_url": title.icon_url, "banner_url": title.banner_url, "display_genre": title.genre.name, "release_date_on_eshop": str(title.date), "retail_sales": False, "eshop_sales": is_downloadable, "web_sales": is_downloadable, "demo_available": False, "aoc_available": False, "in_app_purchase": title.in_app_purchase, "new": title.new, "public": title.public}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def agreement_send_info(request, region):
|
||||
return JsonResponse({"text":{"type":"html","body":"This is useless shit that could break your\naccess to Let's Shop! in the future\ndon't accept plz"}})
|
||||
|
||||
@csrf_exempt
|
||||
def searchcategory(request, region):
|
||||
all_category = searchCategory.objects.all().order_by("-id")
|
||||
categories = []
|
||||
for category in all_category:
|
||||
categories.append({"name": category.name, "params": {"param": [{"key": "platform[]", "value": category.platform_list}]}, "id": category.id})
|
||||
res = {"search_categories":{"search_category_group":[{"name":"Search categories","search_category":categories}]}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def genres(request, region):
|
||||
all_genres = genre.objects.all().order_by("-id")
|
||||
genres = []
|
||||
for agenre in all_genres:
|
||||
genres.append({"name": agenre.name, "id": agenre.id})
|
||||
res = {"genres": {"genre": genres}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def publishers(request, region):
|
||||
all_publishers = publisher.objects.all().order_by("-id")
|
||||
publishers = []
|
||||
for apublisher in all_publishers:
|
||||
publishers.append({"name": apublisher.publisher_name, "id": apublisher.id})
|
||||
res = {"publishers": {"publisher": publishers}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def contents(request, region):
|
||||
search_term = unquote(request.GET.get("freeword"))
|
||||
all_titles = Title.objects.filter(name__icontains=search_term, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
total = all_titles.count()
|
||||
movies = movie.objects.filter(name__icontains=search_term).order_by('-date')
|
||||
total_movie = movies.count()
|
||||
total = total+total_movie
|
||||
titles = []
|
||||
i = 0
|
||||
for title in all_titles:
|
||||
if title.is_not_downloadable:
|
||||
is_downloadable = False
|
||||
else:
|
||||
is_downloadable = True
|
||||
titles.append({"title": {"platform": {"name": title.platform.name, "id": title.platform.id, "device": "CTR", "category": title.genre.id}, "publisher": {"name": title.publisher.publisher_name, "id": title.publisher.id}, "display_genre": title.genre.name, "release_date_on_eshop": str(title.date), "retail_sales": False, "eshop_sales": is_downloadable, "demo_available": False, "aoc_available": False, "in_app_purchase": title.in_app_purchase, "release_date_on_original": str(title.date), "name": title.name, "id": title.id, "product_code": title.product_code, "icon_url": title.icon_url, "banner_url": title.banner_url, "new": title.new}, "index": i})
|
||||
i = i + 1
|
||||
for Movie in movies:
|
||||
if i > 25:
|
||||
continue
|
||||
if Movie.is_3d:
|
||||
dimension = "3d"
|
||||
else:
|
||||
dimension = "2d"
|
||||
titles.append({"movie": {"name": Movie.name, "banner_url": Movie.banner_url, "thumbnail_url": Movie.thumbnail_url, "files": {"file": [{"format": "moflex", "movie_url": Movie.moflex_url, "width": 400, "height": 200, "dimension": dimension, "play_time_sec": Movie.time_in_sec}]}, "id": Movie.id, "new": Movie.new}, "index": i})
|
||||
i = i + 1
|
||||
res = {"contents": {"content": titles, "length": len(titles), "offset": int(request.GET.get("offset")), "total": total}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def titles(request, region):
|
||||
if request.GET.get("platform[]") == None and request.GET.get("genre[]") == None and request.GET.get("publisher[]") == None and request.GET.get("price_max")==None and request.GET.get("price_min")==None and request.GET.get("title[]") == None:
|
||||
if request.GET.get("freeword") != None:
|
||||
search_term = unquote(request.GET.get("freeword"))
|
||||
all_titles = Title.objects.filter(name__icontains=search_term, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("release_date_after") == None:
|
||||
movies = movie.objects.filter(name__icontains=search_term).order_by('-date')
|
||||
if request.GET.get('title[]') == None:
|
||||
all_titles = Title.objects.filter(public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("release_date_after") == None:
|
||||
movies = movie.objects.all().order_by('-date')
|
||||
total = all_titles.count()
|
||||
if request.GET.get("release_date_after") == None:
|
||||
total_movie = movies.count()
|
||||
total = total+total_movie
|
||||
if request.GET.get("platform[]") != None or request.GET.get("genre[]") != None or request.GET.get("publisher[]") != None or request.GET.get("price_max")!=None or request.GET.get("price_min")!=None:
|
||||
#over complicated but at least works
|
||||
if request.GET.get("platform[]") == None:
|
||||
platforms = []
|
||||
all_platforms = platform.objects.all()
|
||||
for aplatform in all_platforms:
|
||||
platforms.append(aplatform.id)
|
||||
else:
|
||||
platforms = request.GET.get("platform[]").split(",")
|
||||
if request.GET.get("genre[]") == None:
|
||||
genrel = []
|
||||
all_genre = genre.objects.all()
|
||||
for agenre in all_genre:
|
||||
genrel.append(agenre.id)
|
||||
else:
|
||||
genrel = request.GET.get("genre[]").split(",")
|
||||
if request.GET.get("publisher[]") == None:
|
||||
publisherl = []
|
||||
all_publisher = publisher.objects.all()
|
||||
for apublisher in all_publisher:
|
||||
publisherl.append(apublisher.id)
|
||||
else:
|
||||
publisherl = request.GET.get("publisher[]").split(",")
|
||||
if request.GET.get("freeword") != None:
|
||||
search_term = unquote(request.GET.get("freeword"))
|
||||
if request.GET.get("price_max") != None and request.GET.get("price_min") == None:
|
||||
all_titles = Title.objects.filter(price__lte=int(request.GET.get("price_max")), name__icontains=search_term,platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_min") != None and request.GET.get("price_max") == None:
|
||||
all_titles = Title.objects.filter(price__gte=int(request.GET.get("price_min")),name__icontains=search_term,platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_max") != None and request.GET.get("price_min") != None:
|
||||
all_titles = Title.objects.filter(price__lte=int(request.GET.get("price_max")),price__gte=int(request.GET.get("price_min")),name__icontains=search_term,platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_max") == None and request.GET.get("price_min")==None:
|
||||
all_titles = Title.objects.filter(name__icontains=search_term,platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
else:
|
||||
if request.GET.get("price_max") != None and request.GET.get("price_min") == None:
|
||||
all_titles = Title.objects.filter(price__lte=int(request.GET.get("price_max")), platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_min") != None and request.GET.get("price_max") == None:
|
||||
all_titles = Title.objects.filter(price__gte=int(request.GET.get("price_min")), platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_max") != None and request.GET.get("price_min") != None:
|
||||
all_titles = Title.objects.filter(price__lte=int(request.GET.get("price_max")),price__gte=int(request.GET.get("price_min")),platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
if request.GET.get("price_max") == None and request.GET.get("price_min")==None:
|
||||
all_titles = Title.objects.filter(platform__in=platforms, genre__in=genrel, publisher__in=publisherl, public=True).order_by("-date")[int(request.GET.get("offset")):25+25]
|
||||
total = all_titles.count()
|
||||
if request.GET.get("title[]") != None:
|
||||
title_ids = request.GET.get("title[]").split(",")
|
||||
all_titles = Title.objects.filter(id__in=title_ids)
|
||||
total = all_titles.count()
|
||||
titles = []
|
||||
i = 0
|
||||
for title in all_titles:
|
||||
#check date
|
||||
if request.GET.get("release_date_after"):
|
||||
now = datetime.date.today()
|
||||
time_between_insertion = now - title.date
|
||||
if int(time_between_insertion.days) > 90:
|
||||
continue
|
||||
if title.is_not_downloadable:
|
||||
is_downloadable = False
|
||||
else:
|
||||
is_downloadable = True
|
||||
titles.append({"title": {"platform": {"name": title.platform.name, "id": title.platform.id, "device": "CTR", "category": title.genre.id}, "publisher": {"name": title.publisher.publisher_name, "id": title.publisher.id}, "display_genre": title.genre.name, "release_date_on_eshop": str(title.date), "retail_sales": False, "eshop_sales": is_downloadable, "demo_available": False, "aoc_available": False, "in_app_purchase": title.in_app_purchase, "release_date_on_original": str(title.date), "name": title.name, "id": title.id, "product_code": title.product_code, "icon_url": title.icon_url, "banner_url": title.banner_url, "new": title.new}, "index": i})
|
||||
i = i + 1
|
||||
try:
|
||||
for Movie in movies:
|
||||
if i > 25:
|
||||
continue
|
||||
if Movie.is_3d:
|
||||
dimension = "3d"
|
||||
else:
|
||||
dimension = "2d"
|
||||
titles.append({"movie": {"name": Movie.name, "banner_url": Movie.banner_url, "thumbnail_url": Movie.thumbnail_url, "files": {"file": [{"format": "moflex", "movie_url": Movie.moflex_url, "width": 400, "height": 200, "dimension": dimension, "play_time_sec": Movie.time_in_sec}]}, "id": Movie.id, "new": Movie.new}, "index": i})
|
||||
i = i + 1
|
||||
except:
|
||||
pass
|
||||
if request.GET.get("offset") == None:
|
||||
offset = 0
|
||||
else:
|
||||
offset = int(request.GET.get("offset"))
|
||||
res = {"contents": {"content": titles, "length": len(titles), "offset": offset, "total": total}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def viewmovie(request, region, mid):
|
||||
try:
|
||||
Movie = movie.objects.get(id=mid)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({"error": True})
|
||||
if Movie.is_3d:
|
||||
dimension = "3d"
|
||||
else:
|
||||
dimension = "2d"
|
||||
res = {"movie": {"name": Movie.name, "banner_url": Movie.banner_url, "thumbnail_url": Movie.thumbnail_url, "files": {"file": [{"format": "moflex", "movie_url": Movie.moflex_url, "width": 400, "height": 200, "dimension": dimension, "play_time_sec": Movie.time_in_sec}]}, "id": Movie.id, "new": Movie.new}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def movies_content(request, region):
|
||||
movies = movie.objects.all().order_by('-date')[int(request.GET.get("offset")):25+25]
|
||||
total = movies.count()
|
||||
all_movies = []
|
||||
i = 0
|
||||
for Movie in movies:
|
||||
if request.GET.get("release_date_after"):
|
||||
now = datetime.date.today()
|
||||
time_between_insertion = now - Movie.date
|
||||
if int(time_between_insertion.days) > 7:
|
||||
continue
|
||||
if Movie.is_3d:
|
||||
dimension = "3d"
|
||||
else:
|
||||
dimension = "2d"
|
||||
all_movies.append({"movie": {"name": Movie.name, "banner_url": Movie.banner_url, "thumbnail_url": Movie.thumbnail_url, "files": {"file": [{"format": "moflex", "movie_url": Movie.moflex_url, "width": 400, "height": 200, "dimension": dimension, "play_time_sec": Movie.time_in_sec}]}, "id": Movie.id, "new": Movie.new}, "index": i})
|
||||
i = i + 1
|
||||
res = {"contents": {"content": all_movies, "length": len(all_movies), "offset": int(request.GET.get("offset")), "total": total}}
|
||||
return JsonResponse(res)
|
||||
|
||||
@csrf_exempt
|
||||
def rankings(request, region):
|
||||
return JsonResponse({"error": {"code": "5626", "message": "WIP. Not ready yet."}}, status=400)
|
||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
django==4.1.6
|
||||
pyctr==0.6.0
|
||||
Flask=2.2.2
|
||||
0
shopdeck/__init__.py
Normal file
0
shopdeck/__init__.py
Normal file
16
shopdeck/asgi.py
Normal file
16
shopdeck/asgi.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
ASGI config for shopdeck project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
133
shopdeck/settings.py
Normal file
133
shopdeck/settings.py
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
"""
|
||||
Django settings for shopdeck project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.1.6.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'somestring'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'shopdeckdb.apps.ShopdeckdbConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_extensions',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'shopdeck.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'shopdeck.wsgi.application'
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.django.project.com/en/4.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
# Server URLS (dont include a trailing slash at the end)
|
||||
SOAP_URL = "soap.example.com"
|
||||
METADATA_API_URL = "api.example.com"
|
||||
|
||||
# TOS
|
||||
TOS_ESHOP = "This is YOUR own custom shop!\nStart customizing it!\n(change this message in shopdeck/settings.py)"
|
||||
|
||||
#dont touch
|
||||
SESSION_COOKIE_NAME = "JSESSIONID"
|
||||
23
shopdeck/urls.py
Normal file
23
shopdeck/urls.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
"""shopdeck URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.1/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('ninja/ws/', include('api.urls')),
|
||||
path('samurai/ws/<str:region>/', include('metadata.urls')),
|
||||
]
|
||||
16
shopdeck/wsgi.py
Normal file
16
shopdeck/wsgi.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for shopdeck project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopdeck.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
0
shopdeckdb/__init__.py
Normal file
0
shopdeckdb/__init__.py
Normal file
18
shopdeckdb/admin.py
Normal file
18
shopdeckdb/admin.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from django.contrib import admin
|
||||
from .models import *
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register(Client3DS)
|
||||
admin.site.register(customTitleID)
|
||||
admin.site.register(Title)
|
||||
admin.site.register(ownedTitle)
|
||||
admin.site.register(wishlistedTitle)
|
||||
admin.site.register(announcement)
|
||||
admin.site.register(motd)
|
||||
admin.site.register(category)
|
||||
admin.site.register(publisher)
|
||||
admin.site.register(genre)
|
||||
admin.site.register(platform)
|
||||
admin.site.register(redeemableCard)
|
||||
admin.site.register(searchCategory)
|
||||
admin.site.register(movie)
|
||||
6
shopdeckdb/apps.py
Normal file
6
shopdeckdb/apps.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ShopdeckdbConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'shopdeckdb'
|
||||
0
shopdeckdb/migrations/__init__.py
Normal file
0
shopdeckdb/migrations/__init__.py
Normal file
135
shopdeckdb/models.py
Normal file
135
shopdeckdb/models.py
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
class Client3DS(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
consoleid = models.CharField(max_length=12, null=False)
|
||||
devicetoken = models.CharField(max_length=21, null=False)
|
||||
is_terminated = models.BooleanField(default=False)
|
||||
balance = models.IntegerField(default=0)
|
||||
language = models.CharField(max_length=3, null=False)
|
||||
region = models.CharField(max_length=3, null=False)
|
||||
country = models.CharField(max_length=3, null=False)
|
||||
def __str__(self):
|
||||
return "3DS "+self.consoleid
|
||||
|
||||
class customTitleID(models.Model):
|
||||
tid = models.CharField(max_length=18, null=False)
|
||||
related_to = models.ForeignKey(Client3DS, null=False, on_delete=models.CASCADE)
|
||||
def __str__(self):
|
||||
return "Title "+self.tid+" for user "+self.related_to.consoleid
|
||||
|
||||
class publisher(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
publisher_name = models.CharField(max_length=20)
|
||||
def __str__(self):
|
||||
return self.publisher_name
|
||||
|
||||
class category(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
index = models.IntegerField(default=0, null=False)
|
||||
name = models.CharField(max_length=25)
|
||||
standard = models.BooleanField(default=False)
|
||||
icon_url = models.TextField(null=False)
|
||||
banner_url = models.TextField(null=False)
|
||||
new = models.BooleanField(default=True)
|
||||
order = models.IntegerField(default=0)
|
||||
def __str__(self):
|
||||
return "Category "+self.name
|
||||
|
||||
class genre(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
name = models.CharField(max_length=50)
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class platform(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
name = models.CharField(max_length=50)
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Title(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
tid = models.CharField(max_length=16, null=False)
|
||||
name = models.CharField(max_length=25)
|
||||
desc = models.TextField(default="", null=False)
|
||||
thumbnail_url = models.TextField(null=False)
|
||||
icon_url = models.TextField(null=False)
|
||||
banner_url = models.TextField(null=False)
|
||||
publisher = models.ForeignKey(publisher, on_delete=models.CASCADE)
|
||||
date = models.DateField(auto_now_add=True, null=False)
|
||||
product_code = models.CharField(max_length=30)
|
||||
new = models.BooleanField(default=True)
|
||||
public = models.BooleanField(default=True)
|
||||
category = models.ForeignKey(category, on_delete=models.DO_NOTHING, null=True, blank=True)
|
||||
genre = models.ForeignKey(genre, null=False, on_delete=models.CASCADE)
|
||||
in_app_purchase = models.BooleanField(default=False)
|
||||
platform = models.ForeignKey(platform, null=False, on_delete=models.CASCADE)
|
||||
price = models.IntegerField(default=0, null=False)
|
||||
version = models.IntegerField(default=1024)
|
||||
is_not_downloadable = models.BooleanField(default=False)
|
||||
ticket_id = models.CharField(max_length=16, null=False)
|
||||
ticket = models.TextField(null=False)
|
||||
size = models.IntegerField(default=0)
|
||||
ticket_available = models.BooleanField(default=True)
|
||||
def __str__(self):
|
||||
return self.name+" by "+self.publisher.publisher_name+" published on "+str(self.date)
|
||||
|
||||
class movie(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
name = models.CharField(max_length=25)
|
||||
thumbnail_url = models.TextField(null=False)
|
||||
banner_url = models.TextField(null=False)
|
||||
is_3d = models.BooleanField(default=False)
|
||||
moflex_url = models.TextField(null=False)
|
||||
time_in_sec = models.IntegerField(null=False)
|
||||
date = models.DateField(auto_now_add=True, null=False)
|
||||
category = models.ForeignKey(category, on_delete=models.DO_NOTHING, null=True, blank=True)
|
||||
new = models.BooleanField(default=True, null=False)
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class ownedTitle(models.Model):
|
||||
title = models.ForeignKey(Title, null=False, on_delete=models.CASCADE)
|
||||
owner = models.ForeignKey(Client3DS, null=False, on_delete=models.CASCADE)
|
||||
def __str__(self):
|
||||
return "Title "+self.title.name+" owned by "+self.owner.consoleid
|
||||
|
||||
class wishlistedTitle(models.Model):
|
||||
title = models.ForeignKey(Title, null=False, on_delete=models.CASCADE)
|
||||
owner = models.ForeignKey(Client3DS, null=False, on_delete=models.CASCADE)
|
||||
def __str__(self):
|
||||
return "Wishlisted title "+self.title.name+" wanted by "+self.owner.consoleid
|
||||
|
||||
class announcement(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
title = models.CharField(max_length=50, null=False)
|
||||
content = models.TextField(null=False)
|
||||
date = models.DateTimeField(auto_now_add=True, null=False)
|
||||
is_banner = models.BooleanField(default=False)
|
||||
banner_url = models.TextField(null=True, blank=True)
|
||||
def __str__(self):
|
||||
return "Announcement "+self.title
|
||||
|
||||
class motd(models.Model):
|
||||
content = models.TextField(null=False)
|
||||
order = models.IntegerField(default=0)
|
||||
def __str__(self):
|
||||
return self.content
|
||||
|
||||
class redeemableCard(models.Model):
|
||||
code = models.CharField(max_length=16, null=False)
|
||||
used = models.BooleanField(default=False)
|
||||
is_money = models.BooleanField(default=True)
|
||||
content = models.CharField(max_length=16, null=False)
|
||||
def __str__(self):
|
||||
return self.code
|
||||
|
||||
class searchCategory(models.Model):
|
||||
id = models.IntegerField(primary_key=True, blank=True)
|
||||
name = models.CharField(max_length=35)
|
||||
platform_list = models.TextField()
|
||||
def __str__(self):
|
||||
return self.name
|
||||
1
templates/cas/listTitlesEx.xml
Normal file
1
templates/cas/listTitlesEx.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<ListTitlesExResponse xmlns="urn:cas.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ListResultTotalSize>1</ListResultTotalSize><Titles><TitleId>{{ t.tid }}</TitleId><Attributes><Name>MaxUserFileSize</Name><Value>{{ t.size }}</Value></Attributes><Attributes><Name>Version</Name><Value>{{ t.version }}</Value></Attributes></Titles></ListTitlesExResponse>{% endblock %}
|
||||
1
templates/ecs/accountListETicketIds.xml
Normal file
1
templates/ecs/accountListETicketIds.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<AccountListETicketIdsResponse xmlns="urn:ecs.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode>{% for custom in customtid %}<TIV>{{ custom.tid }}</TIV>{% endfor %}</AccountListETicketIdsResponse>{% endblock %}
|
||||
1
templates/ecs/deleteSavedCard.xml
Normal file
1
templates/ecs/deleteSavedCard.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<DeleteSavedCardResponse xmlns="urn:ecs.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode></DeleteSavedCardResponse>{% endblock %}
|
||||
1
templates/ecs/getAccountETickets.xml
Normal file
1
templates/ecs/getAccountETickets.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<AccountGetETicketsResponse xmlns="urn:ecs.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode><ETickets>{{ t.ticket }}</ETickets><Certs>AAEAA3BBOO+7vaFqmH3ZATJtHJRZSEyIooYbkaMSWHrnDvYjfsUOEDLcOd3ompao6FnXapim5+NqDP41LKiTBYI0/4M/yzsDgR6fDcDZpS+ARbSy+UEbZ6UcRLXvjOd71tVrp1c0oYVt5tS+1tOiQsfIeRs0IjdeXHeavwcvdpXvoPdby4N4n8MOP+TMg5IgeEBjiUnH9ohWX2SbdNY9jVj/rdpXHpVUQmsTGPxGiYPUyKViiwa2/F1QfBPnoYrBUR621i6lRI+DUBRHqa+z7MKQPJ3VL5Iqyazb71jGAhhI2W4ghzLT0dnZ6kQNkWIcepnbiEPFnB8uLH2bV31RLBZtb34arUp3SjdEfnj+ICHhSpXREqBoraAZ9GPHpVaFqrtoiLkkZIPRi5yAb0dJGDMXgjRKS4UxM0smMDJj2dLrT0u5lgKzUvauQEbGml5+jkoY75vAot7WExBBcBL9gkzBFs+3xMH37HF3oXRGy96W8+3Yj80FLwuIikX9rytjE1T0DRbl+pwsTtqY55jRXmBG3FNj8wlrLGB6nY3VWxUCpqx9PMjYxXWZjn15aRDIBMSVI1BX6R7NJjfJwYRRUaxrmgSQrj7G9HdAoNsLo20HWVbO5zVOo+mk8nILJlUMfTlDJLwMt+kxfYqGYfQhkf8QsIJWzj/SW3ReUZSQa01hy0wuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUm9vdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDQTAwMDAwMDAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAe+jvbLJ5yeLu4SHG6vRP9jn4jweLS3ftn5VgsDWCgbUOVatyERWhd3A8ejD+OunvHGC8HZdGdrI6aMwEsZhSW8lo8R3i21Dk2efwceVi2uIJIjPp02P2HdfBn/OkqR6PZVPUcd17hLnxuM5zNfD1VAVjoeq4OWPgm+kBAR+ZVGNhKHAg6cwNq0h/FA1mJqGDbScRHyBo3kdyFJFRz2nGG6YO+dlJoPcfVJny05rSjHAFNIKTxDH/vTP2vKYNxxleorzFbSALr20G0JxB243pxyAVTKSDK2nAjGnNOwc6AGNgL0YtM4BhpepskVzVYjV5w+tkzkTvWG0UuqqINAGbPuvu03kAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==</Certs><Certs>AAEABJGevkZK0PVSzRty54hJEM9VqfAuUHiWQdiWaD3ABb0K6ocHnYrChMZ1Bl90yL83yIBEQJUCoCKYC7itSDg/bSinneOWJsyysioPGeQQMvCUs5/wEzFG3sj2wanVXNKNnhxHs9EfT1QmwseAE1onddPKZ5vH6DTw4PtY5ohgpxMw/JV5F5PI+6k1p6aQjyKd7ioMprmyOxLUlab+GdDXJkghaHhgWmZTjb83aJmQXTRF/Fxyeg4T4OLIlxyc+mxgZ4h1cypOdVI9L1YvEqq9FXO/BslAVK76gacUF6+aSgZtD/xa1kurKLH/YGYfRDfUnh4NlBLrS8rPTP1qNAiEeYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVhTMDAwMDAwMGMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATegiUrVBbtsZ+LlvdajvsQ9kQx3LpzCkNpYWIt33MEWgLs+KfTqu7JumMJgGYXAQbsUN45okYGq13BWjpKKK5gWfuPhDQcr7vH6Ivoqo+E/EeGDapKkKB73Cq9ORimYIhxvu5vdAX5qxZBJTpzqmFnOstKkwXZvLDORLFjxSoA+NvzNzM3BP9eud8enjZl+asw1VX4NPp62S0PJL0xQ1npgLes5GwZmHNMogL1kkSrxy8txYqBvAlZdOw7OT87N2uikk0247mfzAXmGIhFV0THGw/CasZRcIGrHDJQrNvSaEYO814tuS0fGxcrA+NYviXxpU90S8otwxbffdRgZqYNGUmJQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</Certs></AccountGetETicketsResponse>{% endblock %}
|
||||
1
templates/ecs/getAccountStatus.xml
Normal file
1
templates/ecs/getAccountStatus.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends "header.xml" %}{% block main %}<GetAccountStatusResponse xmlns="urn:ecs.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode><AccountId>{{ accountid }}</AccountId><AccountStatus>R</AccountStatus><Balance><Amount>{{ balance }}</Amount><Currency>CREDIT</Currency></Balance><EulaVersion>0</EulaVersion><Country>{{ country }}</Country><Region>{{ region }}</Region><AccountAttributes><Name>LOYALTY_LOGIN_NAME</Name><Value></Value></AccountAttributes>{% for custom in customtid %}<TIV>{{ custom.tid }}</TIV>{% endfor %}<ServiceURLs><Name>ContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>UncachedContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>SystemContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>SystemUncachedContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>EcsURL</Name><URI>https://{{ setting.SOAP_URL }}/ecs/services/ECommerceSOAP</URI></ServiceURLs><ServiceURLs><Name>IasURL</Name><URI>https://{{ setting.SOAP_URL }}/ias/services/IdentityAuthenticationSOAP</URI></ServiceURLs><ServiceURLs><Name>CasURL</Name><URI>https://{{ setting.SOAP_URL }}/cas/services/CatalogingSOAP</URI></ServiceURLs><ServiceURLs><Name>NusURL</Name><URI>https://nus.c.shop.nintendowifi.net/nus/services/NetUpdateSOAP</URI></ServiceURLs><IVSSyncFlag>false</IVSSyncFlag><CountryAttribits>15</CountryAttribits></GetAccountStatusResponse>{% endblock %}
|
||||
1
templates/ecs/getAccountStatusError.xml
Normal file
1
templates/ecs/getAccountStatusError.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<GetAccountStatusResponse xmlns="urn:ecs.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>903</ErrorCode><ErrorMessage>IAS - Invalid device token</ErrorMessage><ServiceStandbyMode>false</ServiceStandbyMode><AccountId>{{ accountid }}</AccountId><AccountStatus>R</AccountStatus><EulaVersion>0</EulaVersion><Country>{{ country }}</Country><Region>{{ region }}</Region><ServiceURLs><Name>ContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>UncachedContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>SystemContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>SystemUncachedContentPrefixURL</Name><URI>https://{{ setting.SOAP_URL }}/ccs/download</URI></ServiceURLs><ServiceURLs><Name>EcsURL</Name><URI>https://{{ setting.SOAP_URL }}/ecs/services/ECommerceSOAP</URI></ServiceURLs><ServiceURLs><Name>IasURL</Name><URI>https://{{ setting.SOAP_URL }}/ias/services/IdentityAuthenticationSOAP</URI></ServiceURLs><ServiceURLs><Name>CasURL</Name><URI>https://{{ setting.SOAP_URL }}/cas/services/CatalogingSOAP</URI></ServiceURLs><ServiceURLs><Name>NusURL</Name><URI>https://nus.c.shop.nintendowifi.net/nus/services/NetUpdateSOAP</URI></ServiceURLs><IVSSyncFlag>false</IVSSyncFlag></GetAccountStatusResponse>{% endblock %}
|
||||
1
templates/header.xml
Normal file
1
templates/header.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body>{% block main %}{% endblock %}</soapenv:Body></soapenv:Envelope>
|
||||
1
templates/ias/getChallenge.xml
Normal file
1
templates/ias/getChallenge.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<GetChallengeResponse xmlns="urn:ias.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode><Challenge>526726942</Challenge></GetChallengeResponse>{% endblock %}
|
||||
1
templates/ias/register.xml
Normal file
1
templates/ias/register.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<RegisterResponse xmlns="urn:ias.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode><AccountId>{{ accountid }}</AccountId><DeviceToken>{{ devicetoken }}</DeviceToken><Country>{{ country }}</Country><ExtAccountId></ExtAccountId></RegisterResponse>{% endblock %}
|
||||
1
templates/ias/setIVSData.xml
Normal file
1
templates/ias/setIVSData.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<SetIVSDataResponse xmlns="urn:ias.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode></SetIVSDataResponse>{% endblock %}
|
||||
1
templates/ias/unregister.xml
Normal file
1
templates/ias/unregister.xml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{% extends 'header.xml' %}{% block main %}<UnregisterResponse xmlns="urn:ias.wsapi.broadon.com"><Version>2.0</Version><DeviceId>{{ id }}</DeviceId><MessageId>{{ message }}</MessageId><TimeStamp>{{ time }}</TimeStamp><ErrorCode>0</ErrorCode><ServiceStandbyMode>false</ServiceStandbyMode></UnregisterResponse>{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue