Files
k-boris-website/backlogger/views.py
Boris f820e86277
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
steam sync
2026-04-02 21:11:54 +03:00

240 lines
7.9 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', '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 = Item.objects.create(
user=request.user,
category=Item.GAMES,
name=game['name'],
hours_played=hours,
progress_percent=progress,
steam_appid=game['appid'],
)
hltb_api.apply_to_item(item)
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}")