243 lines
8.0 KiB
Python
243 lines
8.0 KiB
Python
from django.conf import settings
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.shortcuts import render, get_object_or_404, redirect
|
|
from django.urls import reverse
|
|
from .models import Item, UserProfile
|
|
from .forms import ItemForm, ProfileForm, SignupForm
|
|
from . import steam as steam_api
|
|
from . import hltb as hltb_api
|
|
|
|
|
|
def signup(request):
|
|
if request.method == 'POST':
|
|
form = SignupForm(request.POST)
|
|
if form.is_valid():
|
|
user = form.save(commit=False)
|
|
user.is_active = False
|
|
user.save()
|
|
return render(request, 'backlogger/signup_pending.html')
|
|
else:
|
|
form = SignupForm()
|
|
return render(request, 'backlogger/signup.html', {'form': form})
|
|
|
|
|
|
SORT_MAP = {
|
|
'fav': ['-favorite', 'name'],
|
|
'az': ['name'],
|
|
'za': ['-name'],
|
|
'newest': ['-created_at'],
|
|
'oldest': ['created_at'],
|
|
'progress': ['-progress_percent'],
|
|
'updated': ['-updated_at'],
|
|
}
|
|
|
|
|
|
@login_required
|
|
def profile(request):
|
|
user_profile, _ = UserProfile.objects.get_or_create(user=request.user)
|
|
if request.method == 'POST':
|
|
form = ProfileForm(request.POST, instance=user_profile)
|
|
if form.is_valid():
|
|
saved = form.save()
|
|
request.session['theme'] = saved.theme
|
|
return redirect('backlogger:profile')
|
|
else:
|
|
form = ProfileForm(instance=user_profile)
|
|
request.session['theme'] = user_profile.theme
|
|
return render(request, 'backlogger/profile.html', {'form': form, 'profile': user_profile})
|
|
|
|
|
|
@login_required
|
|
def item_list(request):
|
|
category = request.GET.get('category', '')
|
|
sort = request.GET.get('sort', '')
|
|
if sort in SORT_MAP:
|
|
request.session['sort'] = sort
|
|
else:
|
|
sort = request.session.get('sort', 'fav')
|
|
shelf = request.GET.get('shelf', Item.ACTIVE)
|
|
if shelf not in (Item.ACTIVE, Item.COMPLETED, Item.ABANDONED, Item.UNENDING):
|
|
shelf = Item.ACTIVE
|
|
|
|
items = Item.objects.filter(user=request.user, status=shelf)
|
|
if category:
|
|
items = items.filter(category=category)
|
|
items = items.order_by(*SORT_MAP.get(sort, SORT_MAP['fav']))
|
|
|
|
return render(request, 'backlogger/list.html', {
|
|
'items': items,
|
|
'category': category,
|
|
'sort': sort,
|
|
'shelf': shelf,
|
|
'categories': Item.CATEGORY_CHOICES,
|
|
'debug': settings.DEBUG,
|
|
})
|
|
|
|
|
|
@login_required
|
|
def item_add(request):
|
|
if request.method == 'POST':
|
|
form = ItemForm(request.POST)
|
|
if form.is_valid():
|
|
item = form.save(commit=False)
|
|
item.user = request.user
|
|
item.save()
|
|
hltb_api.apply_to_item(item)
|
|
return redirect('backlogger:list')
|
|
else:
|
|
form = ItemForm()
|
|
return render(request, 'backlogger/item_form.html', {'form': form, 'action': 'Add'})
|
|
|
|
|
|
@login_required
|
|
def item_edit(request, pk):
|
|
item = get_object_or_404(Item, pk=pk, user=request.user)
|
|
if request.method == 'POST':
|
|
form = ItemForm(request.POST, instance=item)
|
|
if form.is_valid():
|
|
updated = form.save()
|
|
if 'name' in form.changed_data or 'category' in form.changed_data:
|
|
hltb_api.apply_to_item(updated)
|
|
return redirect('backlogger:list')
|
|
else:
|
|
form = ItemForm(instance=item)
|
|
return render(request, 'backlogger/item_form.html', {'form': form, 'action': 'Edit', 'item': item})
|
|
|
|
|
|
@login_required
|
|
def item_set_status(request, pk):
|
|
if request.method == 'POST':
|
|
item = get_object_or_404(Item, pk=pk, user=request.user)
|
|
new_status = request.POST.get('status')
|
|
if new_status in (Item.ACTIVE, Item.COMPLETED, Item.ABANDONED, Item.UNENDING):
|
|
item.status = new_status
|
|
item.save(update_fields=['status', 'updated_at'])
|
|
next_url = request.POST.get('next') or reverse('backlogger:list')
|
|
return redirect(next_url)
|
|
|
|
|
|
@login_required
|
|
def item_delete(request, pk):
|
|
if request.method == 'POST':
|
|
get_object_or_404(Item, pk=pk, user=request.user).delete()
|
|
return redirect('backlogger:list')
|
|
|
|
|
|
@login_required
|
|
def steam_login(request):
|
|
callback = request.build_absolute_uri(reverse('backlogger:steam_callback'))
|
|
realm = f"{request.scheme}://{request.get_host()}"
|
|
return redirect(steam_api.build_auth_url(callback, realm))
|
|
|
|
|
|
@login_required
|
|
def steam_callback(request):
|
|
steam_id = steam_api.verify_and_get_steam_id(request.GET.dict())
|
|
if not steam_id:
|
|
return render(request, 'backlogger/steam_import.html', {'error': 'Steam verification failed. Please try again.'})
|
|
|
|
api_key = getattr(settings, 'STEAM_API_KEY', '')
|
|
if not api_key:
|
|
return render(request, 'backlogger/steam_import.html', {'error': 'Steam API key is not configured on the server.'})
|
|
|
|
try:
|
|
games = steam_api.get_owned_games(api_key, steam_id)
|
|
except Exception:
|
|
return render(request, 'backlogger/steam_import.html', {'error': 'Could not fetch your Steam library. Your profile may be set to private.'})
|
|
|
|
existing = set(
|
|
Item.objects.filter(user=request.user, category=Item.GAMES)
|
|
.values_list('name', flat=True)
|
|
)
|
|
|
|
game_list = []
|
|
for g in games:
|
|
name = g.get('name', '')
|
|
hours = round(g.get('playtime_forever', 0) / 60, 1)
|
|
game_list.append({
|
|
'appid': g.get('appid'),
|
|
'name': name,
|
|
'hours': hours,
|
|
'already_imported': name in existing,
|
|
})
|
|
|
|
request.session['steam_games'] = game_list
|
|
return render(request, 'backlogger/steam_import.html', {'games': game_list})
|
|
|
|
|
|
@login_required
|
|
def steam_import(request):
|
|
if request.method != 'POST':
|
|
return redirect('backlogger:list')
|
|
|
|
games_by_appid = {str(g['appid']): g for g in request.session.get('steam_games', [])}
|
|
selected = request.POST.getlist('appids')
|
|
|
|
imported = 0
|
|
for appid in selected:
|
|
game = games_by_appid.get(appid)
|
|
if not game or game['already_imported']:
|
|
continue
|
|
hours = game['hours']
|
|
progress = min(100.0, hours) if hours > 0 else 0.0
|
|
Item.objects.create(
|
|
user=request.user,
|
|
category=Item.GAMES,
|
|
name=game['name'],
|
|
hours_played=hours,
|
|
progress_percent=progress,
|
|
steam_appid=game['appid'],
|
|
)
|
|
imported += 1
|
|
|
|
del request.session['steam_games']
|
|
return redirect(f"{reverse('backlogger:list')}?category=games&imported={imported}")
|
|
|
|
|
|
@login_required
|
|
def debug_delete_all(request):
|
|
if not settings.DEBUG:
|
|
return redirect('backlogger:list')
|
|
if request.method == 'POST':
|
|
Item.objects.filter(user=request.user).delete()
|
|
return redirect('backlogger:list')
|
|
|
|
|
|
@login_required
|
|
def steam_sync_login(request):
|
|
callback = request.build_absolute_uri(reverse('backlogger:steam_sync_callback'))
|
|
realm = f"{request.scheme}://{request.get_host()}"
|
|
return redirect(steam_api.build_auth_url(callback, realm))
|
|
|
|
|
|
@login_required
|
|
def steam_sync_callback(request):
|
|
steam_id = steam_api.verify_and_get_steam_id(request.GET.dict())
|
|
if not steam_id:
|
|
return redirect(f"{reverse('backlogger:list')}?sync_error=1")
|
|
|
|
api_key = getattr(settings, 'STEAM_API_KEY', '')
|
|
if not api_key:
|
|
return redirect(f"{reverse('backlogger:list')}?sync_error=1")
|
|
|
|
try:
|
|
games = steam_api.get_owned_games(api_key, steam_id)
|
|
except Exception:
|
|
return redirect(f"{reverse('backlogger:list')}?sync_error=1")
|
|
|
|
hours_by_appid = {
|
|
g['appid']: round(g.get('playtime_forever', 0) / 60, 1)
|
|
for g in games
|
|
}
|
|
|
|
steam_items = Item.objects.filter(user=request.user, steam_appid__isnull=False)
|
|
synced = 0
|
|
for item in steam_items:
|
|
new_hours = hours_by_appid.get(item.steam_appid)
|
|
if new_hours is not None and new_hours != item.hours_played:
|
|
item.hours_played = new_hours
|
|
item.save(update_fields=['hours_played', 'updated_at'])
|
|
synced += 1
|
|
|
|
return redirect(f"{reverse('backlogger:list')}?category=games&synced={synced}")
|