Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- Fetch HLTB main/extra/completionist hours when a game item is saved - Re-fetch only when name or category changes on edit - Steam imports also fetch HLTB for each selected game - Cards show compact HLTB row: "HLTB: 40h · +extra 60h · 100% 100h" - Edit form shows HLTB breakdown as a hint next to Total hours field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
158 lines
5.0 KiB
Python
158 lines
5.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
|
|
from .forms import ItemForm, 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'],
|
|
}
|
|
|
|
|
|
@login_required
|
|
def item_list(request):
|
|
category = request.GET.get('category', '')
|
|
sort = request.GET.get('sort', 'fav')
|
|
|
|
items = Item.objects.filter(user=request.user)
|
|
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,
|
|
'categories': Item.CATEGORY_CHOICES,
|
|
})
|
|
|
|
|
|
@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_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 = Item.objects.create(
|
|
user=request.user,
|
|
category=Item.GAMES,
|
|
name=game['name'],
|
|
hours_played=hours,
|
|
progress_percent=progress,
|
|
)
|
|
hltb_api.apply_to_item(item)
|
|
imported += 1
|
|
|
|
del request.session['steam_games']
|
|
return redirect(f"{reverse('backlogger:list')}?category=games&imported={imported}")
|