class BrowseReplaysDTView(Django17DatatablesView):
    model = Replay
    fields = (
        "title",
        "unixTime",
        "gametype",
        "download_count",
        "comment_count",
        "gameID",
        "map_info__name",
    )

    # safe GET data for use in global_search()
    def get(self, request, *args, **kwargs):
        self._GET = request.GET
        try:
            return super(Django17DatatablesView, self).get(request, *args, **kwargs)
        except AttributeError:
            return super(Django17DatatablesView, self).get(request, (), {})

    def global_search(self, queryset):
        """Filter a queryset with global search"""
        for k, v in self._GET.items():
            if k.startswith("btnfilter") and v.strip():
                queryset = replay_filter(queryset, v)
        search = self.dt_data["sSearch"]
        if search:
            search_fields = list()
            for k, v in self.dt_data.items():
                if k.startswith("bSearchable_") and v is True:
                    index = int(k.split("bSearchable_")[1])
                    search_fields.append(self.get_db_fields()[index])
            if self.dt_data["bRegex"]:
                criterions = [Q(**{"%s__iregex" % field: search}) for field in search_fields if self.can_regex(field)]
                if len(criterions) > 0:
                    search = reduce(or_, criterions)
                    queryset = queryset.filter(search)
            else:
                for term in search.split():
                    criterions = (Q(**{"%s__icontains" % field: term}) for field in search_fields)
                    search = reduce(or_, criterions)
                    queryset = queryset.filter(search)
        return queryset class CommentDTView(Django17DatatablesView):
    model = Comment
    fields = (
        "submit_date",
        "user_name",
        "comment",
        "user__userprofile__accountid",
        "object_pk",
    )

    def global_search(self, queryset):
        return super(CommentDTView, self).global_search(queryset.filter(is_removed=False)) def ajax_map_lookup(request, name):
    maps = Map.objects.filter(name__icontains=name).distinct().values("id", "name")
    return HttpResponse(ujson.dumps({"maps": list(maps)})) def ajax_player_lookup(request, name):
    pa = (
        PlayerAccount.objects.exclude(accountid=0)
        .filter(player__name__icontains=name)
        .distinct()
        .select_related("player__name")
        .order_by("player__name")
        .only("accountid", "player__name")
        .values("accountid", "player__name")
    )
    return HttpResponse(ujson.dumps({"player": list(pa)})) def ajax_playerrating_tbl_src(request, accountid):
    empty_result = {"iTotalRecords": 0, "iTotalDisplayRecords": 0, "aaData": list()}
    try:
        sEcho = int(request.GET["sEcho"])
        empty_result["sEcho"] = sEcho
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("trouble reading 'sEcho': %s", exc)
        return HttpResponse(ujson.dumps(empty_result))
    try:
        accountid = int(accountid)
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("accountid '%s' is not an integer: %s", accountid, exc)
        return HttpResponse(ujson.dumps(empty_result))
    if accountid == 0:
        return HttpResponse(ujson.dumps(empty_result))
    try:
        pa = PlayerAccount.objects.get(accountid=accountid)
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("cannot get PlayerAccount for accountid '%d': %s", accountid, exc)
        return HttpResponse(ujson.dumps(empty_result))

    ratings = list()
    if pa.accountid > 0:
        for game in pa.get_all_games().exclude(sldb_name=""):
            if not Rating.objects.filter(game=game, playeraccount=pa).exists():
                continue
            user = request.user if request.user.is_authenticated else None
            try:
                skills = get_sldb_playerskill(game.sldb_name, [pa.accountid], user, True)[0]
            except SLDBError as exc:
                logger.error("Retrieving skill for player %s for game %s: %s", pa, game, exc)
                continue
            else:
                if pa != skills["account"]:
                    logger.error(
                        "Requested (%s) and returned (%s) PlayerAccounts do not match!",
                        pa,
                        skills["account"],
                    )
                    continue
                if skills["status"] == 0:
                    if pa.sldb_privacy_mode != skills["privacyMode"]:
                        pa.sldb_privacy_mode = skills["privacyMode"]
                        pa.save()
                    for mt, i in settings.SLDB_SKILL_ORDER:
                        ratings.append(
                            [
                                game.name,
                                Rating.objects.filter(match_type=mt).first().get_match_type_display(),
                                skills["skills"][i][0],
                            ]
                        )

    return HttpResponse(
        ujson.dumps(
            {
                "sEcho": sEcho,
                "iTotalRecords": len(ratings),
                "iTotalDisplayRecords": len(ratings),
                "aaData": ratings,
            }
        )
    ) def ajax_playerreplays_tbl_src(request, accountid):
    empty_result = {"iTotalRecords": 0, "iTotalDisplayRecords": 0, "aaData": list()}
    params = dict()
    for k, v in request.GET.items():
        try:
            if k[0] == "i":
                params[k] = int(v)
            elif k[0] == "s" or k[0] == "m":
                params[k] = MySQLdb.escape_string(v)
            elif k[0] == "b":
                params[k] = v == "true"
            elif k[0] == "_":
                pass
            else:
                raise Exception("Unhandled parameter type")
        except Exception as exc:
            logger.error("FIXME: to broad exception handling.")
            logger.exception("trouble reading request.GET['%s']='%s', Exception: %s", k, v, exc)
            return HttpResponse(ujson.dumps(empty_result))
    empty_result["sEcho"] = params["sEcho"]
    try:
        accountid = int(accountid)
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("accountid '%s' is not an integer: %s", accountid, exc)
        return HttpResponse(ujson.dumps(empty_result))
    if accountid == 0:
        return HttpResponse(ujson.dumps(empty_result))
    try:
        pa = PlayerAccount.objects.get(accountid=accountid)
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("cannot get PlayerAccount for accountid '%d': %s", accountid, exc)
        return HttpResponse(ujson.dumps(empty_result))

    qs = Replay.objects.filter(player__account__accountid=accountid)
    if params["sSearch"]:
        qs = qs.filter(title__icontains=params["sSearch"])

    if "iSortCol_0" in params:
        if params.get("sSortDir_0", "") == "desc":
            order = "-"
        else:
            order = ""
        if params["iSortCol_0"] == 0:
            qs = qs.order_by("{}title".format(order))
        elif params["iSortCol_0"] == 1:
            qs = qs.order_by("{}unixTime".format(order))

    replays = list()
    for replay in qs[params["iDisplayStart"] : params["iDisplayStart"] + params["iDisplayLength"]]:
        try:
            replays.append(
                [
                    replay.title,
                    replay.unixTime.strftime("%Y-%m-%d %H:%M:%S"),
                    replay._playername(pa),
                    replay.game.name,
                    replay.match_type,
                    replay._result(pa),
                    replay._faction(pa),
                    replay.gameID,
                ]
            )
        except ObjectDoesNotExist:
            return HttpResponseNotFound("<h1>Player not found</h1>")
    res = {
        "sEcho": params["sEcho"],
        "iTotalRecords": Replay.objects.filter(player__account__accountid=accountid).count(),
        "iTotalDisplayRecords": qs.count(),
        "aaData": replays,
    }
    for k, v in res.items():
        if isinstance(v, bytes):
            res[k] = v.decode("utf-8")
    return HttpResponse(ujson.dumps(res)) def ajax_winloss_tbl_src(request, accountid):
    empty_result = {"iTotalRecords": 0, "iTotalDisplayRecords": 0, "aaData": list()}
    try:
        sEcho = int(request.GET["sEcho"])
        empty_result["sEcho"] = sEcho
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("trouble reading 'sEcho': %s", exc)
        return HttpResponse(ujson.dumps(empty_result))
    try:
        accountid = int(accountid)
    except ValueError as exc:
        logger.exception("accountid '%s' is not an integer: %s", accountid, exc)
        return HttpResponse(ujson.dumps(empty_result))
    if accountid == 0:
        return HttpResponse(ujson.dumps(empty_result))
    try:
        pa = PlayerAccount.objects.get(accountid=accountid)
    except ObjectDoesNotExist as exc:
        logger.error("cannot get PlayerAccount for accountid '%d': %s", accountid, exc)
        return HttpResponse(ujson.dumps(empty_result))

    win_loss_data = list()
    for game in pa.get_all_games().exclude(sldb_name=""):
        try:
            player_stats = get_sldb_player_stats(game.sldb_name, pa.accountid)
        except SLDBError as exc:
            logger.error("Retrieving stats for player %s for game %s: %s", pa, game, exc)
            continue
        else:
            for match_type in ["Duel", "Team", "FFA", "TeamFFA"]:
                total = reduce(lambda x, y: x + y, player_stats[match_type], 0)
                if total == 0:
                    continue
                try:
                    ratio = float(player_stats[match_type][1] * 100) / float(total)
                except ZeroDivisionError:
                    if player_stats[match_type][1] > 0:
                        ratio = 1
                    else:
                        ratio = 0
                win_loss_data.append(
                    [
                        game.name,
                        match_type if match_type != "Duel" else "1v1",
                        total,
                        player_stats[match_type][1],
                        player_stats[match_type][0],
                        player_stats[match_type][2],
                        "%3.0f" % ratio + " %",
                    ]
                )

    return HttpResponse(
        ujson.dumps(
            {
                "sEcho": sEcho,
                "iTotalRecords": len(win_loss_data),
                "iTotalDisplayRecords": len(win_loss_data),
                "aaData": win_loss_data,
            }
        )
    ) def enginelinks_modal(request, gameID):
    c = downloadlinks(gameID, "engine")
    return render(request, "modal_enginelinks.html", c) def gamerelease_modal(request, gameid):
    c = {"gameversions": GameRelease.objects.filter(game__id=gameid).order_by("-id")}
    return render(request, "modal_gameversions.html", c) def hof_tbl_src(request, leaderboardid):
    empty_result = {"iTotalRecords": 0, "iTotalDisplayRecords": 0, "aaData": list()}
    try:
        sEcho = int(request.GET["sEcho"])
        empty_result["sEcho"] = sEcho
    except Exception as exc:
        logger.error("FIXME: to broad exception handling.")
        logger.exception("trouble reading 'sEcho': %s", exc)
        return HttpResponse(ujson.dumps(empty_result))

    lps = list(
        SldbLeaderboardPlayer.objects.filter(leaderboard__id=int(leaderboardid)).values_list(
            "rank",
            "account__preffered_name",
            "trusted_skill",
            "estimated_skill",
            "uncertainty",
            "inactivity",
            "account__accountid",
        )
    )
    return HttpResponse(
        ujson.dumps(
            {
                "sEcho": sEcho,
                "iTotalRecords": len(lps),
                "iTotalDisplayRecords": len(lps),
                "aaData": lps,
            }
        )
    ) def maplinks_modal(request, gameID):
    c = downloadlinks(gameID, "map")
    return render(request, "modal_maplinks.html", c) def modlinks_modal(request, gameID):
    c = downloadlinks(gameID, "game")
    return render(request, "modal_modlinks.html", c) def ratinghistorygraph_modal(request, game_abbr, accountid, match_type):
    c = {
        "game_abbr": game_abbr,
        "game_verbose": Game.objects.get(sldb_name=game_abbr).name,
        "accountid": accountid,
        "match_type": match_type,
        "match_type_verbose": SldbPlayerTSGraphCache.match_type2sldb_name[match_type],
    }
    return render(request, "modal_rating_history_graph.html", c) def stats_modal(request, gameID):
    c = {}
    try:
        # player stats
        ps = PlayerStats.objects.get(replay__gameID=gameID).decompressed
        # team stats
        ts = dict(
            (_ts["stat_type"], _ts["pk"])
            for _ts in TeamStats.objects.filter(replay__gameID=gameID).values("pk", "stat_type")
        )  # evaluate filter immediately to get all TeamStats objects with one SQL query
    except (PlayerStats.DoesNotExist, TeamStats.DoesNotExist):
        c["error"] = (
            "No statistics have been found for this match. That happens when the replay file is very old, "
            "incomplete or broken."
        )
    else:
        # player stats
        stat_order = (
            "mouseClicks",
            "mousePixels",
            "keyPresses",
            "numCommands",
            "unitCommands",
        )
        c["player_stats_header"] = (
            "Player",
            "MC/min",
            "MP/min",
            "KP/min",
            "Cmd/min",
            "Units/cmd",
        )
        player_colors = dict(
            (player.name.lower(), player.team.rgbcolor)
            for player in Player.objects.filter(replay__gameID=gameID, spectator=False)
        )
        c["player_stats"] = (
            (
                player,
                player_colors.get(player.lower(), ""),
                [
                    0.0
                    if p_stats["numCommands"] == 0
                    else p_stats[s] / float(p_stats["numCommands"])
                    if s == "unitCommands"
                    else p_stats[s] / 60.0
                    for s in stat_order
                ],
            )
            for player, p_stats in ps.items()
        )
        # team stats
        # sort by stats type
        c["team_stats"] = []
        for graphid, label in TeamStats.graphid2label.items():
            try:
                c["team_stats"].append((label, ts[graphid]))
            except KeyError:
                c["error_ts"] = (
                    "No or incomplete team statistics. Autohosts don't create them. Upload your own "
                    "demofile to see them."
                )
    return render(request, "modal_stats.html", c) class GameFeed(Feed):
    description_template = "feeds_replay_description.html"

    def get_object(self, request, game):
        return get_object_or_404(Game, name=game)

    def title(self, game):
        return "Replay uploads for %s" % game.name

    def link(self, game):
        return game.get_absolute_url()

    def description(self, game):
        return "Newest %s replays" % game.name

    def items(self, game):
        gr_names = GameRelease.objects.filter(game=game).values_list("name", flat=True)
        return Replay.objects.filter(gametype__in=gr_names).order_by("-upload_date")[:20]

    def item_title(self, replay):
        return super(GameFeed, self).item_title(replay.title)

    def item_pubdate(self, item):
        return item.unixTime

    def item_author_name(self, item):
        if item.autohostname:
            return item.autohostname
        else:
            return str() class LatestUploadsFeed(Feed):
    title = "Spring replay uploads"
    link = "/"
    description = "Newest replay uploads"
    description_template = "feeds_replay_description.html"

    def items(self):
        return Replay.objects.order_by("-upload_date")[:20]

    def item_title(self, replay):
        return super(LatestUploadsFeed, self).item_title(replay.title)

    def item_pubdate(self, item):
        return item.unixTime

    def item_author_name(self, item):
        if item.autohostname:
            return item.autohostname
        else:
            return str() class SRSLatestCommentFeed(LatestCommentFeed):
    def item_author_name(self, item):
        return item.user.username

    def item_title(self, item):
        dots = "..." if len(item.comment) > 50 else ""
        return super(SRSLatestCommentFeed, self).item_title(item.user.username + ": " + item.comment[:50] + dots)

    def item_description(self, item):
        return super(SRSLatestCommentFeed, self).item_description(item.user.username + ": " + item.comment) class UploaderFeed(Feed):
    description_template = "feeds_replay_description.html"

    def get_object(self, request, username):
        return get_object_or_404(User, username=username)

    def title(self, user):
        return "Replays uploaded by %s" % user.username

    def link(self, user):
        return user.get_absolute_url()

    def description(self, user):
        return "Newest replays uploaded by %s" % user.username

    def items(self, user):
        return Replay.objects.filter(uploader=user).order_by("-upload_date")[:20]

    def item_title(self, replay):
        return super(UploaderFeed, self).item_title(replay.title)

    def item_pubdate(self, item):
        return item.unixTime

    def item_author_name(self, item):
        if item.autohostname:
            return item.autohostname
        else:
            return str() class HofSitemap(Sitemap):
    changefreq = "weekly"

    def items(self):
        return Game.objects.exclude(sldb_name="")

    def location(self, game):
        return reverse(hall_of_fame, args=[game.abbreviation]) class PlayerAccountSitemap(Sitemap):
    changefreq = "weekly"

    def items(self):
        return PlayerAccount.objects.filter(accountid__gt=0) class ReplaySitemap(Sitemap):
    changefreq = "monthly"

    def items(self):
        return Replay.objects.all() @login_required
def upload(request):
    global timer
    c = all_page_infos(request)
    UploadFormSet = formset_factory(UploadFileForm, extra=5)
    if request.method == "POST":
        formset = UploadFormSet(request.POST, request.FILES)
        replays = []
        if formset.is_valid():
            for form in formset:
                if form.cleaned_data:
                    logger.info(
                        "upload by request.user=%r form.cleaned_data=%r",
                        request.user,
                        form.cleaned_data,
                    )
                    ufile = form.cleaned_data["file"]
                    short = form.cleaned_data["short"]
                    long_text = form.cleaned_data["long_text"]
                    tags = form.cleaned_data["tags"]
                    timer = SrsTiming()
                    timer.start("upload()")
                    (path, written_bytes) = save_uploaded_file(ufile.read(), ufile.name)
                    logger.info(
                        "User '%s' uploaded file '%s' with title '%s', parsing it now.",
                        request.user,
                        os.path.basename(path),
                        short[:20],
                    )
                    if written_bytes != ufile.size:
                        logger.warning(
                            "written_bytes=%r != ufile.size=%r",
                            written_bytes,
                            ufile.size,
                        )
                    try:
                        replay, msg = parse_uploaded_file(path, timer, tags, short, long_text, request.user)
                        logger.debug("replay=%r msg=%r", replay, msg)
                        replays.append((True, replay))
                    except BadFileType:
                        form._errors = {"file": ["Not a spring demofile: %s." % ufile.name]}
                        replays.append((False, "Not a spring demofile: %s." % ufile.name))
                        continue
                    except AlreadyExistsError as exc:
                        form._errors = {"file": ['Uploaded replay already exists: "{}"'.format(exc.replay.title)]}
                        replays.append(
                            (
                                False,
                                'Uploaded replay already exists: <a href="{}">{}</a>.'.format(
                                    exc.replay.get_absolute_url(), exc.replay.title
                                ),
                            )
                        )
                        continue
                    except Exception as exc:
                        form._errors = {"file": ["Server error: {}".format(exc)]}
                        replays.append((False, "Server error. Please contact admin."))
                        logger.exception(
                            "Exception >> %s << when parsing form.cleaned_data=%r",
                            exc,
                            form.cleaned_data,
                        )
                        continue
                    finally:
                        timer.stop("upload()")
                    logger.info("timings:\n%s", timer)

        if len(replays) == 0:
            logger.error("no replay created, this shouldn't happen")
        elif len(replays) == 1:
            if replays[0][0]:
                return HttpResponseRedirect(replays[0][1].get_absolute_url())
            else:
                # fall through to get back on page with error msg
                pass
        else:
            c["replays"] = replays
            c["replay_details"] = True
            return render(request, "multi_upload_success.html", c)
    else:
        # form = UploadFileForm()
        formset = UploadFormSet()
    c["formset"] = formset
    return render(request, "upload.html", c) @login_required
def upload_media(request, gameID):
    c = all_page_infos(request)

    replay = get_object_or_404(Replay, gameID=gameID)
    if request.user not in get_owner_list(replay.uploader):
        return HttpResponseRedirect(replay.get_absolute_url())

    UploadMediaFormSet = formset_factory(UploadMediaForm, extra=5)
    c["replay"] = replay
    c["replay_details"] = True

    if request.method == "POST":
        logger.debug("request.FILES: %s", request.FILES)
        formset = UploadMediaFormSet(request.POST, request.FILES)
        if formset.is_valid():
            c["media_files"] = list()
            for form in formset:
                if form.cleaned_data:
                    logger.info("form.cleaned_data=%s", form.cleaned_data)
                    media = form.cleaned_data["media_file"]
                    image = form.cleaned_data["image_file"]
                    comment = form.cleaned_data["comment"]
                    if media:
                        media.seek(0)
                        media_magic_text = magic.from_buffer(media.read(1024))
                        media.seek(0)
                        media_magic_mime = magic.from_buffer(media.read(1024), mime=True)
                        media.seek(0)
                    else:
                        media_magic_text = None
                        media_magic_mime = None
                    erm = ExtraReplayMedia.objects.create(
                        replay=replay,
                        uploader=request.user,
                        comment=comment,
                        media=media,
                        image=image,
                        media_magic_text=media_magic_text,
                        media_magic_mime=media_magic_mime,
                    )
                    c["media_files"].append(erm)
                    logger.info(
                        "User '%s' uploaded for replay:'%s' media:'%s' img:'%s' with comment:'%s'.",
                        request.user,
                        replay,
                        erm.media,
                        erm.image,
                        erm.comment[:20],
                    )
            return render(request, "upload_media_success.html", c)
        else:
            logger.error("formset.errors: %s", formset.errors)
            logger.error("request.FILES: %s", request.FILES)
            logger.error("request.POST: %s", request.POST)
    else:
        formset = UploadMediaFormSet()
    c["formset"] = formset
    return render(request, "upload_media.html", c) def all_comments(request):
    c = all_page_infos(request)
    return render(request, "comments.html", c) def browse_archive(request, bfilter):
    c = all_page_infos(request)

    for browse_filter in [
        "t_today",
        "t_yesterday",
        "t_this_month",
        "t_last_month",
        "t_this_year",
        "t_last_year",
        "t_ancient",
    ]:
        c[browse_filter] = replay_filter(Replay.objects.all(), "date {}".format(browse_filter))

    try:
        sist = SiteStats.objects.get(id=1)
    except ObjectDoesNotExist:
        sist = update_stats.now()

    tags = list(
        map(
            lambda x: (Tag.objects.get(id=int(x.split(".")[0])), x.split(".")[1]),
            sist.tags.split("|"),
        )
    )
    c["top_tags"] = list()
    for t in range(0, 12, 3):
        if t + 3 > len(tags):
            break
        c["top_tags"].append((tags[t], tags[t + 1], tags[t + 2]))
    maps = list(
        map(
            lambda x: (Map.objects.get(id=int(x.split(".")[0])), x.split(".")[1]),
            sist.maps.split("|"),
        )
    )
    c["top_maps"] = list()
    for r in range(0, 8, 2):
        if r + 2 > len(maps):
            break
        c["top_maps"].append((maps[r], maps[r + 1]))
    c["top_players"] = map(
        lambda x: (PlayerAccount.objects.get(id=int(x.split(".")[0])), x.split(".")[1]),
        sist.active_players.split("|"),
    )
    c["all_games"] = map(
        lambda x: (Game.objects.get(id=int(x.split(".")[0])), x.split(".")[1]),
        sist.games.split("|"),
    )
    c["replays_num"] = Replay.objects.count()
    c["gr_all"] = GameRelease.objects.all()
    c["tags_all"] = Tag.objects.all()
    c["maps_all"] = Map.objects.all()
    c["pa_num"] = PlayerAccount.objects.exclude(accountid__lte=0).count()
    c["ah_num"] = Replay.objects.values("autohostname").distinct().count()
    c["user_num"] = len([user for user in User.objects.all() if user.replays_uploaded() > 0])
    c["first_replay"] = Replay.objects.first()
    c["last_replay"] = Replay.objects.last()
    hosts = dict()
    for host in Replay.objects.values_list("autohostname", flat=True):
        if host:
            try:
                hosts[host] += 1
            except KeyError:
                hosts[host] = 0
    c["autohosts"] = [(name, count) for name, count in hosts.items() if count > 0]
    c["autohosts"].sort(key=operator.itemgetter(1), reverse=True)
    c["uploaders"] = [
        (user.username, user.replays_uploaded()) for user in User.objects.all() if user.replays_uploaded() > 0
    ]
    c["uploaders"].sort(key=operator.itemgetter(1), reverse=True)

    if bfilter and bfilter.strip():
        bfilter = str(MySQLdb.escape_string(bfilter))
        args = bfilter.split("/")
        filters_ = map(lambda x: x.split("="), args)
        # only accept "date=1224/tag=8v8" etc
        c["filters"] = list()
        have = list()
        for filter_ in filters_:
            if (
                len(filter_) == 2
                and filter_[1].strip()
                and filter_[0]
                in [
                    "date",
                    "map",
                    "tag",
                    "game",
                    "gameversion",
                    "player",
                    "autohost",
                    "uploader",
                ]
                and filter_[0] not in have
            ):
                try:
                    if filter_[0] == "date":
                        pass
                    elif filter_[0] == "map":
                        c["map_name"] = Map.objects.get(id=filter_[1]).name
                    elif filter_[0] == "tag":
                        Tag.objects.get(id=filter_[1])
                    elif filter_[0] == "game":
                        Game.objects.get(id=filter_[1])
                    elif filter_[0] == "gameversion":
                        gr = GameRelease.objects.get(id=filter_[1])
                        c["game_abbreviation"] = "{} {}".format(gr.game.abbreviation, gr.version)
                    elif filter_[0] == "player":
                        PlayerAccount.objects.get(id=filter_[1])
                    elif filter_[0] == "autohost":
                        Replay.objects.filter(autohostname=filter_[1])[0]
                    elif filter_[0] == "uploader":
                        Replay.objects.filter(uploader__username=filter_[1])[0]
                    else:
                        raise Exception("unknown filter type '%s'" % filter_[0])
                    # all fine, add filter
                    c["filters"].append((filter_[0], filter_[1]))
                    have.append(filter_[0])
                except Exception as exc:
                    # object doesnt exist
                    logger.exception("FIXME: to broad exception handling.")
                    logger.debug("invalid filter_: '%s' Exception: %s", filter_, exc)
    else:
        c["filters"] = ""
    return render(request, "browse_archive.html", c) def download(request, gameID):
    replay = get_object_or_404(Replay, gameID=gameID)

    replay.download_count += 1
    replay.save()

    path = os.path.join(replay.path, replay.filename)
    try:
        filemagic = magic.from_file(path, mime=True)
    except IOError:
        errmsg = "File for replay(id=%r) %r not found: %r" % (replay.id, replay, path)
        logger.error(errmsg)
        raise Http404(errmsg)
    if filemagic.endswith("gzip") and not replay.filename.endswith(".sdfz"):
        myopen = gzip.open
    else:
        myopen = open
    if replay.filename.endswith(".gz"):
        filename = replay.filename[:-3]
    else:
        filename = replay.filename
    with myopen(path, "rb") as demofile:
        response = HttpResponse(demofile.read(), content_type="application/x-spring-demo")
    response["Content-Disposition"] = 'attachment; filename="%s"' % filename
    return response @login_required
@never_cache
def edit_replay(request, gameID):
    c = all_page_infos(request)
    try:
        replay = Replay.objects.prefetch_related().get(gameID=gameID)
        c["replay"] = replay
    except ObjectDoesNotExist:
        raise Http404("No replay with ID {!r} found.".format(strip_tags(gameID)))

    if request.user != replay.uploader:
        return render(request, "edit_replay_wrong_user.html", c)

    if request.method == "POST":
        form = EditReplayForm(request.POST)
        if form.is_valid():
            short = request.POST["short"]
            long_text = request.POST["long_text"]
            tags = request.POST["tags"]

            for tag in replay.tags.all():
                if tag.replay_count == 1 and tag.pk > 10:
                    # this tag was used only by this replay and is not one of the default ones (see srs/sql/tag.sql)
                    tag.delete()
            replay.tags.clear()
            autotag = set_autotag(replay)
            save_tags(replay, tags)
            save_desc(replay, short, long_text, autotag)
            replay.save()
            logger.info(
                "User '%s' modified replay '%s': short: '%s' title:'%s' long_text:'%s' tags:'%s'",
                request.user,
                replay.gameID,
                replay.short_text,
                replay.title,
                replay.long_text,
                ", ".join(Tag.objects.filter(replay=replay).values_list("name", flat=True)),
            )
            return HttpResponseRedirect(replay.get_absolute_url())
    else:
        form = EditReplayForm(
            {
                "short": replay.short_text,
                "long_text": replay.long_text,
                "tags": ", ".join(Tag.objects.filter(replay=replay).values_list("name", flat=True)),
            }
        )
    c["form"] = form
    c["replay_details"] = True

    return render(request, "edit_replay.html", c) def hall_of_fame(request, abbreviation):
    c = all_page_infos(request)
    game = get_object_or_404(Game, abbreviation=abbreviation)

    if game.sldb_name == "ZK":
        pass
    elif game.sldb_name != "":
        try:
            c["leaderboards"] = get_sldb_leaderboards(game)
        except SLDBError as exc:
            logger.error("get_sldb_leaderboards(%r): %s", game, exc)
    else:
        c["errmsg"] = "No ratings available for this game. Please choose one from the menu."
        logger.error("%s (%s)", c["errmsg"], game)

    if abbreviation == "ZK":
        c["intro_text"] = [
            "<b>The official Hall of Fame of Zero-K is at <a "
            'href="http://zero-k.info/Ladders">http://zero-k.info/Ladders</a>.</b><br/>No rating '
            "records are kept on this site anymore."
        ]
    c["games"] = Game.objects.exclude(sldb_name="")
    c["ladders"] = [x[1] for x in RatingBase.MATCH_TYPE_CHOICES]
    #    games_with_bawards = Game.objects.filter(
    #       gamerelease__name__in=BAwards.objects.values_list("replay__gametype", flat=True).distinct()).distinct()
    # FIXME: show awards that belong to each game separately. for now only BA.
    games_with_bawards = Game.objects.filter(name="Balanced Annihilation")
    if game in games_with_bawards:
        try:
            sist = SiteStats.objects.get(id=1)
        except ObjectDoesNotExist:
            sist = update_stats.now()

        c["bawards"] = sist.bawards_decoded
        c["bawards_lu"] = sist.last_modified
    c["thisgame"] = game
    return render(request, "hall_of_fame.html", c) def index(request):
    c = all_page_infos(request)
    if "game_pref_obj" in c:
        replays = Replay.objects.filter(
            published=True,
            gametype__in=c["game_pref_obj"].gamerelease_set.values_list("name", flat=True),
        )
    else:
        replays = Replay.objects.filter(published=True)
    c["replays"] = replays.order_by("-upload_date")[: settings.INDEX_REPLAY_RANGE]
    c["range"] = settings.INDEX_REPLAY_RANGE
    c["range_end"] = settings.INDEX_REPLAY_RANGE
    c["popular_replays"] = Replay.objects.order_by("-download_count")[:8]
    c["news"] = NewsItem.objects.filter(show=True).order_by("-pk")[:6]
    c["replay_details"] = False
    c["latest_comments"] = Comment.objects.filter(is_removed=False).order_by("-submit_date")[:5]
    return render(request, "index.html", c) def index_replay_range(request, range_end, game_pref):
    c = all_page_infos(request)
    try:
        game_pref = int(game_pref)
    except (TypeError, ValueError):
        pass
    else:
        if "game_pref_obj" not in c and game_pref > 0:
            c["game_pref"] = game_pref
            c["game_pref_obj"] = Game.objects.get(id=game_pref)
    c["range"] = settings.INDEX_REPLAY_RANGE
    c["range_end"] = int(range_end) + settings.INDEX_REPLAY_RANGE
    if "game_pref_obj" in c:
        replays = Replay.objects.filter(
            published=True,
            gametype__in=c["game_pref_obj"].gamerelease_set.values_list("name", flat=True),
        )
    else:
        replays = Replay.objects.filter(published=True)
    c["replays"] = replays.order_by("-upload_date")[int(range_end) : c["range_end"]]
    return render(request, "replay_index_boxes.html", c) @never_cache
def login(request):
    c = all_page_infos(request)
    nexturl = request.GET.get("next", "/")
    if request.method == "POST":
        form = AuthenticationForm(data=request.POST)
        form.fields["password"].max_length = 4096
        if form.is_valid():
            user = form.get_user()
            django_contrib_auth_login(request, user)
            logger.info(
                "Logged in user '%s' (%s) a.k.a '%s'",
                user.username,
                user.last_name,
                user.userprofile.aliases,
            )
            if request.user.userprofile.game_pref_fixed or request.session.get("game_pref", 0) == 0:
                # if pref was set explicitely, always set cookie according to profile
                # or if no cookie set, use profiles setting (even if 0)
                request.session["game_pref"] = request.user.userprofile.game_pref
            else:
                # cookie is already set (!=0), overwrite users pref as it's not fixed
                try:
                    request.user.userprofile.game_pref = int(request.session["game_pref"])
                    request.user.userprofile.save()
                except ValueError:
                    # not int, ignore
                    pass
            return HttpResponseRedirect(nexturl)
        else:
            logger.info("login error: %s", form.errors)
    else:
        form = AuthenticationForm()
    c["next"] = nexturl
    c["form"] = form
    form.fields["password"].max_length = 4096
    return render(request, "login.html", c) @never_cache
def logout(request):

    username = str(request.user)
    # restore game_pref after logout
    game_pref = request.session.get("game_pref", None)
    django_contrib_auth_logout(request)
    logger.info("Logged out user '%s'", username)
    if game_pref:
        request.session["game_pref"] = game_pref
    nexturl = request.GET.get("next")
    if nexturl:
        dest = nexturl
    else:
        dest = "/"
    return HttpResponseRedirect(dest) def media(request, mediaid):
    media = get_object_or_404(ExtraReplayMedia, id=mediaid)
    if media.media_magic_mime == "image/svg+xml":
        c = all_page_infos(request)
        c["media"] = media
        return render(request, "show_svg.html", c)
    else:
        try:
            response = HttpResponse(media.media.read(), content_type=media.media_magic_mime)
            response["Content-Disposition"] = 'attachment; filename="%s"' % media.media_basename
            return response
        except IOError as exc:
            logger.error(
                "Cannot read media from ExtraReplayMedia(%d) of Replay(%d): media '%s'. Exception: %s"
                % (media.id, media.replay.id, media.media_basename, exc)
            )
            raise Http404("Error reading '%s', please contact 'Dansan' in the springrts forum." % media.media_basename) def player(request, accountid):
    c = all_page_infos(request)
    accountid = int(accountid)
    pa = get_object_or_404(PlayerAccount, accountid=accountid)
    c["pagetitle"] = "Player {}".format(pa.preffered_name)
    c["pagedescription"] = "Statistics and match history of player %s" % pa.preffered_name
    c["playeraccount"] = pa
    c["PA"] = pa
    c["all_names"] = pa.get_names()
    bawards = pa.bawards
    if any(pa.bawards.values()):
        c["bawards"] = bawards
    xtawards = pa.xtawards
    if any(xtawards):
        c["xtawards"] = xtawards
    cursed_awards = pa.cursed_awards
    if cursed_awards:
        c["cursed_awards"] = cursed_awards

    if not respect_privacy(request, accountid):
        c["ts_history_games"] = pa.get_all_games_no_bots().exclude(sldb_name="")
    return render(request, "player.html", c) def replay(request, gameID):
    c = all_page_infos(request)

    if not gameid_re.findall(gameID):
        raise Http404("Malformed gameID: %r." % gameID)

    try:
        replay = Replay.objects.prefetch_related().get(gameID=gameID)
        c["replay"] = replay
        c["comment_obj"] = replay
    except ObjectDoesNotExist:
        raise Http404("No replay with gameID {!r} found.".format(strip_tags(gameID)))

    if not replay.published:
        return render(request, "replay_unpublished.html", c)

    game = replay.game_release.game
    match_type = replay.match_type_short

    sldb_connection_error = False
    try:
        match_skills = get_sldb_match_skills([replay.gameID])
        if match_skills:
            match_skills = match_skills[0]
    except SLDBError as exc:
        sldb_connection_error = True
        logger.error("get_sldb_match_skills(%s): %s", [replay.gameID], exc)
        match_skills = {"status": 3}
        # ignore, we'll just use the old values from the DB in the view
    else:
        if match_skills and match_skills["status"] == 0:
            # update skill data in DB
            logger.debug("got match data for %s from sldb", replay)
            for player in match_skills["players"]:
                if isinstance(player["account"], dict):
                    player["account"] = PlayerAccount.objects.get(pk=player["account"]["pk"])
                pa = player["account"]
                pa_skill = pa.get_rating(game, match_type)
                mu, si = player["skills"][1]
                if pa_skill.trueskill_mu != mu or pa_skill.trueskill_sigma != si:
                    try:
                        playername = Player.objects.get(account=pa, replay=replay, spectator=False).name
                    except ObjectDoesNotExist:
                        playername = "??"
                    pa_skill.trueskill_mu = mu
                    pa_skill.trueskill_sigma = si
                    if pa_skill.playername == "" or pa_skill.playername == "??":
                        pa_skill.playername = playername
                    pa_skill.save()
                    defaults = dict(
                        match_date=replay.unixTime,
                        playername=playername,
                        trueskill_mu=mu,
                        trueskill_sigma=si,
                    )
                    RatingHistory.objects.update_or_create(
                        match=replay,
                        game=game,
                        match_type=match_type,
                        playeraccount=pa,
                        defaults=defaults,
                    )
                if pa.sldb_privacy_mode != player["privacyMode"]:
                    pa.sldb_privacy_mode = player["privacyMode"]
                    pa.save()
                if not replay.rated:
                    replay.rated = True
                    replay.save()
        else:
            # ignore, we'll just use the old values from the DB in the view
            logger.debug("no match data from SLDB")
            pass

    # fill cache prefetching all entries from DB in one call
    all_players = Player.objects.filter(replay=replay)
    allyteams = Allyteam.objects.filter(replay=replay)
    if (
        not allyteams.filter(winner=True).exists()
        or (replay.upload_date.year >= 2016 and allyteams.filter(winner=True, num=0).exists())
        and not sldb_connection_error
    ):
        # workaround for issue #89: guess winner from ratings
        fix_missing_winner(replay)

    c["allyteams"] = []
    match_rating_history = RatingHistory.objects.filter(match=replay, match_type=match_type)
    [entry for entry in match_rating_history]  # prefetch all ratings of this match by hitting the DB only once
    for at in allyteams:
        playeraccounts = PlayerAccount.objects.filter(player__team__allyteam=at).order_by("player__team__num")
        teams = Team.objects.filter(allyteam=at)
        players = all_players.filter(account__in=playeraccounts)
        players_w_rating = list()
        old_rating = 0
        new_rating = 0
        lobby_rank_sum = 0
        if (
            not replay.rated
            or replay.notcomplete
            or not players.exists()
            or not replay.game_release.game.sldb_name
            or all_players.filter(account__accountid=0).exists()
        ):
            # notcomplete, no SLDB rating or bot present -> no rating
            players_w_rating = [(player, None, None) for player in players]
        else:
            # TrueSkill ratings
            for pa in playeraccounts:
                if match_skills and match_skills["status"] == 0:
                    # use SLDB-provided values
                    def _get_players_skills(pa):
                        for pl in match_skills["players"]:
                            if pl["account"] == pa:
                                return pl

                    pl = _get_players_skills(pa)
                    if pl:
                        pl_new = pl["skills"][1][0]
                        pl_old = pl["skills"][0][0]
                    else:
                        pl_new = pl_old = 25
                        c["skill_error"] = True
                else:
                    # use old method of DB lookups for current and previous matchs DB entries
                    try:
                        pl_new = match_rating_history.get(playeraccount=pa).trueskill_mu
                    except ObjectDoesNotExist:
                        # no rating on this replay
                        pl_new = None
                    try:
                        # find previous TS value
                        pl_old = (
                            RatingHistory.objects.filter(
                                playeraccount=pa,
                                game=game,
                                match_type=match_type,
                                match__unixTime__lt=replay.unixTime,
                            )
                            .order_by("-match__unixTime")[0]
                            .trueskill_mu
                        )
                    except IndexError:
                        pl_old = 25  # default value for new players

                # privatize?
                if playeraccounts.count() > 2 or pa.sldb_privacy_mode == 0:
                    new_rating += pl_new if pl_new else 0
                    old_rating += pl_old if pl_old else 0
                else:
                    new_rating += privatize_skill(pl_new) if pl_new else 0
                    old_rating += privatize_skill(pl_old) if pl_old else 0

                if pa.sldb_privacy_mode != 0 and (
                    not request.user.is_authenticated or pa.accountid != request.user.userprofile.accountid
                ):
                    if pl_new:
                        pl_new = privatize_skill(pl_new)
                    if pl_old:
                        pl_old = privatize_skill(pl_old)
                players_w_rating.append((all_players.get(account=pa, spectator=False), pl_old, pl_new))

        if teams:
            lobby_rank_sum = reduce(
                lambda x, y: x + y,
                [pl.rank for pl in all_players.filter(team__allyteam=at)],
                0,
            )
            c["allyteams"].append((at, players_w_rating, old_rating, new_rating, lobby_rank_sum))

    c["has_bot"] = replay.tags.filter(name="Bot").exists()
    c["specs"] = all_players.filter(replay=replay, spectator=True).order_by("id")
    c["upload_broken"] = UploadTmp.objects.filter(replay=replay).exists()
    c["mapoptions"] = MapOption.objects.filter(replay=replay).order_by("name")
    c["modoptions"] = ModOption.objects.filter(replay=replay).order_by("name")
    c["replay_details"] = True
    c["was_stopped"] = not allyteams.filter(winner=True).exists()
    if c["was_stopped"]:
        logger.info("was_stopped=True: allyteams=%r replay=%r", allyteams, replay)
    c["is_draw"] = allyteams.filter(winner=True).count() > 1
    c["pagedescription"] = "%s %s %s match on %s (%s)" % (
        replay.num_players,
        replay.match_type,
        replay.game_release.game.name,
        replay.map_info.name,
        replay.unixTime,
    )
    c["replay_owners"] = get_owner_list(replay.uploader)
    c["extra_media"] = ExtraReplayMedia.objects.filter(replay=replay)
    c["known_video_formats"] = [
        "video/webm",
        "video/mp4",
        "video/ogg",
        "video/x-flv",
        "application/ogg",
    ]
    c["has_video"] = c["extra_media"].filter(media_magic_mime__in=c["known_video_formats"]).exists()
    c["metadata"] = list()
    if replay.map_info.width > 128:
        # springfiles.springrts.com returnd pixel size
        map_px_x = replay.map_info.width / 512
        map_px_y = replay.map_info.height / 512
    else:
        # springfiles.springrts.com returnd Spring Map Size
        map_px_x = replay.map_info.width
        map_px_y = replay.map_info.height
    try:
        c["metadata"].append(("Size", "{} x {}".format(map_px_x, map_px_y)))
        try:
            c["metadata"].append(
                (
                    "Wind",
                    "{} - {}".format(
                        replay.map_info.metadata2["metadata"]["MinWind"],
                        replay.map_info.metadata2["metadata"]["MaxWind"],
                    ),
                )
            )
        except KeyError:
            pass
        try:
            c["metadata"].append(("Tidal", str(replay.map_info.metadata2["metadata"]["TidalStrength"])))
        except KeyError:
            pass
        for k, v in replay.map_info.metadata2["metadata"].items():
            if type(v) == str and not v.strip():
                continue
            elif type(v) == list and not v:
                continue
            elif k.strip() in [
                "",
                "Width",
                "TidalStrength",
                "MapFileName",
                "MapMinHeight",
                "Type",
                "MapMaxHeight",
                "Resources",
                "Height",
                "MinWind",
                "MaxWind",
                "StartPos",
            ]:
                # either already added above, or ignore uninteresting data
                continue
            else:
                c["metadata"].append((k.strip(), v))
        try:
            if replay.map_info.metadata2["version"]:
                c["metadata"].append(("Version", replay.map_info.metadata2["version"]))
        except KeyError:
            pass
        try:
            c["metadata"].append(
                (
                    "Wind",
                    "{} - {}".format(
                        replay.map_info.metadata2["metadata"]["MinWind"],
                        replay.map_info.metadata2["metadata"]["MaxWind"],
                    ),
                )
            )
        except KeyError:
            pass
        try:
            c["metadata"].append(("Tidal", str(replay.map_info.metadata2["metadata"]["TidalStrength"])))
        except KeyError:
            pass
        for k, v in replay.map_info.metadata2["metadata"].items():
            if type(v) == str and not v.strip():
                continue
            elif type(v) == list and not v:
                continue
            elif k.strip() in [
                "",
                "Width",
                "TidalStrength",
                "MapFileName",
                "MapMinHeight",
                "Type",
                "MapMaxHeight",
                "Resources",
                "Height",
                "MinWind",
                "MaxWind",
                "StartPos",
            ]:
                # either already added above, or ignore uninteresting data
                continue
            else:
                c["metadata"].append((k.strip(), v))
        try:
            if replay.map_info.metadata2["version"]:
                c["metadata"].append(("Version", replay.map_info.metadata2["version"]))
        except KeyError:
            pass
        # create map file on demand if missing (#130)
        sm = SpringMaps(replay.map_info.name)
        replay_image_filepath = sm.get_full_replay_image_filepath(replay.map_info.name, replay.gameID)
        if not os.path.exists(replay_image_filepath):
            sm.create_map_with_boxes(replay)
    except Exception as exc:
        c["metadata"].append(("Error", "Problem with metadata. Please report to Dansan."))
        logger.error("FIXME: to broad exception handling.")
        logger.error(
            "Problem with metadata (replay.id '%d' map.id %d), replay.map_info.metadata2: %r",
            replay.id,
            replay.map_info.id,
            replay.map_info.metadata2,
        )
        logger.exception("Exception: %s", exc)
    c["xtaward_heroes"] = XTAwards.objects.filter(replay=replay, isAlive=1)
    c["xtaward_los"] = XTAwards.objects.filter(replay=replay, isAlive=0)
    c["cursed_awards"] = CursedAwards.objects.filter(replay=replay)

    page_history = request.session.get("page_history")
    if page_history and isinstance(page_history, list):
        # check data (session data is user input)
        for page in list(page_history):
            if not gameid_re.findall(page):
                page_history.remove(page)
        if gameID not in page_history:
            if len(page_history) > 4:
                page_history.remove(page)
            page_history.insert(0, gameID)
    else:
        page_history = [gameID]
    request.session["page_history"] = page_history

    return render(request, "replay.html", c) def replay_by_id(request, replayid):
    try:
        r = Replay.objects.get(id=replayid)
        return HttpResponseRedirect(r.get_absolute_url())
    except ObjectDoesNotExist:
        raise Http404("No replay with ID {!r} found.".format(strip_tags(replayid))) @login_required
@never_cache
def sldb_privacy_mode(request):
    """
    0: Privacy disabled, 1: Basic privacy (default), 2: Full privacy
    """
    c = all_page_infos(request)

    accountid = request.user.userprofile.accountid
    try:
        c["current_privacy_mode"] = get_sldb_pref(accountid, "privacyMode")
    except SLDBError as exc:
        logger.error('get_sldb_pref(%r, "privacyMode"): %s', accountid, exc)
        c["current_privacy_mode"] = -1
    logger.debug(
        "current_privacy_mode: %s (user: %s)",
        str(c["current_privacy_mode"]),
        request.user,
    )

    if request.method == "POST":
        #
        # POST
        #
        form = SLDBPrivacyForm(request.POST)
        if form.is_valid():
            c["in_post"] = True
            new_mode = int(form.cleaned_data["mode"])
            logger.debug("new_mode: %d (user: %s)", new_mode, request.user)
            try:
                set_sldb_pref(accountid, "privacyMode", str(new_mode))
            except:
                logger.exception("FIXME: to broad exception handling.")
                c["new_privacy_mode"] = -1
            else:
                c["new_privacy_mode"] = new_mode
            logger.debug("new_privacy_mode: %d (user: %s)", new_mode, request.user)
    else:
        #
        # GET
        #
        form = SLDBPrivacyForm({"mode": c["current_privacy_mode"]})

    c["form"] = form

    return render(request, "sldb_privacy_mode.html", c) def team_stat_div(request, ts_id):
    ts = TeamStats.objects.get(pk=ts_id)
    ts_reversed = [
        {
            "name": _ts["name"],
            "x": _ts["x"],
            "y": [
                val / 15.0 if index == 0 else (val - _ts["y"][index - 1]) / 15.0 for index, val in enumerate(_ts["y"])
            ],
        }
        for _ts in ts.decompressed
    ]
    div_str = MatchStatsGeneration.get_team_stat_plot(
        TeamStats.graphid2label[ts.stat_type],
        ts_reversed,
        "markers" if ts.stat_type in ("unitsReceived", "unitsSent", "unitsCaptured", "unitsOutCaptured") else "lines",
    )
    return HttpResponse(content=div_str) def ts_history_graph(request, game_abbr, accountid, match_type):
    if respect_privacy(request, accountid):
        with open(os.path.join(settings.IMG_PATH, "tsh_privacy.png"), "rb") as pic:
            response = HttpResponse(pic.read(), content_type="image/png")
        return response
    path = str()
    accountid = int(accountid)
    if match_type not in ["1", "T", "F", "G", "L"]:
        logger.error("Bad argument 'match_type': '%s'.", match_type)
        path = os.path.join(settings.IMG_PATH, "tsh_error.png")
    else:
        try:
            graphs = get_sldb_player_ts_history_graphs(game_abbr, accountid)
        except SLDBError as exc:
            logger.error(
                "get_sldb_player_ts_history_graphs(%r, %d): %s",
                game_abbr,
                accountid,
                exc,
            )
            path = os.path.join(settings.IMG_PATH, "tsh_error.png")
    if not path:
        path = graphs[SldbPlayerTSGraphCache.match_type2sldb_name[match_type]]
    with open(path, "rb") as pic:
        response = HttpResponse(pic.read(), content_type="image/png")
    return response @login_required
@never_cache
def user_settings(request):
    # TODO:
    c = all_page_infos(request)
    up = request.user.userprofile
    if request.method == "POST":
        game_pref_form = GamePref(request.POST)
        if game_pref_form.is_valid():
            up.game_pref_fixed = not game_pref_form.cleaned_data["auto"]
            if game_pref_form.cleaned_data["game_choice"]:
                up.game_pref = int(game_pref_form.cleaned_data["game_choice"])
            else:
                up.game_pref = request.session.get("game_pref", None)
            up.save()
            request.session["game_pref"] = up.game_pref
    else:
        game_pref_form = GamePref(initial={"auto": not up.game_pref_fixed, "game_choice": up.game_pref})
    c["game_pref_form"] = game_pref_form
    return render(request, "settings.html", c)
import django.contrib.sitemaps.views
import django_xmlrpc.views
from django.conf.urls import include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from .ajax_views import (
    BrowseReplaysDTView,
    CommentDTView,
    ajax_map_lookup,
    ajax_player_lookup,
    ajax_playerrating_tbl_src,
    ajax_playerreplays_tbl_src,
    ajax_winloss_tbl_src,
    enginelinks_modal,
    gamerelease_modal,
    hof_tbl_src,
    maplinks_modal,
    modlinks_modal,
    ratinghistorygraph_modal,
    stats_modal,
)
from .feeds import GameFeed, LatestUploadsFeed, SRSLatestCommentFeed, UploaderFeed
from .sitemap import HofSitemap, PlayerAccountSitemap, ReplaySitemap
from .upload_views import upload, upload_media
from .views import (
    all_comments,
    browse_archive,
    download,
    edit_replay,
    hall_of_fame,
    index,
    index_replay_range,
    login,
    logout,
    media,
    player,
    replay,
    replay_by_id,
    sldb_privacy_mode,
    team_stat_div,
    ts_history_graph,
    user_settings,
)


sitemaps = {
    "replays": ReplaySitemap,
    "players": PlayerAccountSitemap,
    "hall of fame": HofSitemap,
}

urlpatterns = [
    url(r"^$", index, name="srs/index"),
    url(
        r"^index_replay_range/(?P<range_end>[\d]+)/(?P<game_pref>[\d]+)/$",
        index_replay_range,
        name="srs/index_replay_range",
    ),
    url(r"^sitemap\.xml$", django.contrib.sitemaps.views.sitemap, {"sitemaps": sitemaps}),
    url(r"^upload/$", upload, name="srs/upload"),
    url(r"^upload_media/(?P<gameID>[0-9,a-f]+)/$", upload_media, name="srs/upload_media"),
    url(r"^media/(?P<mediaid>[0-9]+)/$", media, name="srs/media"),
    url(r"^settings/$", user_settings, name="srs/settings"),
    url(r"^login/$", login, name="srs/login"),
    url(r"^logout/$", logout, name="srs/logout"),
    url(r"^all_comments/", all_comments, name="srs/all_comments"),
    url(r"^comment_tbl_src$", CommentDTView.as_view(), name="srs/comment_tbl_src$"),
    url(r"^comments/", include("django_comments.urls")),
    url(r"^download/(?P<gameID>[0-9a-f]+)/$", download, name="srs/download"),
    url(r"^xmlrpc/$", django_xmlrpc.views.handle_xmlrpc, name="srs/xmlrpc"),
    url(
        r"^maplinks_modal/(?P<gameID>[0-9a-f]+)/$",
        maplinks_modal,
        name="srs/maplinks_modal",
    ),
    url(
        r"^modlinks_modal/(?P<gameID>[0-9a-f]+)/$",
        modlinks_modal,
        name="srs/modlinks_modal",
    ),
    url(
        r"^enginelinks_modal/(?P<gameID>[0-9a-f]+)/$",
        enginelinks_modal,
        name="srs/enginelinks_modal",
    ),
    url(r"^stats_modal/(?P<gameID>[0-9a-f]+)/$", stats_modal, name="srs/stats_modal"),
    url(
        r"^feeds/latest_comments/$",
        SRSLatestCommentFeed(),
        name="srs/feeds/latest_comments",
    ),
    url(r"^feeds/latest/$", LatestUploadsFeed(), name="srs/feeds/latest"),
    url(r"^feeds/game/(?P<game>[\w ]+)/$", GameFeed(), name="srs/feeds/game"),
    url(
        r"^feeds/uploader/(?P<username>[\w\ .:()\[\]-]+)/$",
        UploaderFeed(),
        name="srs/feeds/uploader",
    ),
    url(r"^sldb_privacy_mode/$", sldb_privacy_mode, name="srs/sldb_privacy_mode"),
    url(r"^browse/(?P<bfilter>.*)$", browse_archive, name="srs/browse_archive"),
    url(r"^browse_tbl_src$", BrowseReplaysDTView.as_view(), name="srs/browse_tbl_src"),
    url(r"^replay/(?P<gameID>[0-9,a-f]+)/$", replay, name="srs/replay"),
    url(r"^replay_by_id/(?P<replayid>[\d-]+)/$", replay_by_id, name="srs/replay_by_id"),
    url(r"^edit_replay/(?P<gameID>[0-9a-f]+)/$", edit_replay, name="srs/edit_replay"),
    url(r"^player/(?P<accountid>[\d-]+)/$", player, name="srs/player"),
    url(
        r"^ts_history_graph/(?P<game_abbr>[A-Z0-9]+)/(?P<accountid>[\d]+)/(?P<match_type>[1TFGL])/$",
        ts_history_graph,
        name="srs/ts_history_graph",
    ),
    url(
        r"^ts_history_modal/(?P<game_abbr>[A-Z0-9]+)/(?P<accountid>[\d]+)/(?P<match_type>[1TFGL])/$",
        ratinghistorygraph_modal,
        name="srs/ratinghistorygraph_modal",
    ),
    url(r"^team_stat_div/(?P<ts_id>[\d-]+)/$", team_stat_div, name="srs/team_stat_div"),
    url(
        r"^gamerelease/(?P<gameid>[\d-]+)/$",
        gamerelease_modal,
        name="srs/gamerelease_modal",
    ),
    url(
        r"^hall_of_fame/(?P<abbreviation>[\w\ .:()\[\]-]+)/$",
        hall_of_fame,
        name="srs/hall_of_fame",
    ),
    url(r"^hof_tbl_src/(?P<leaderboardid>[\d-]+)/$", hof_tbl_src, name="srs/hof_tbl_src"),
    url(
        r"^ajax_player_lookup/(?P<name>.+)/$",
        ajax_player_lookup,
        name="srs/ajax_player_lookup",
    ),
    url(r"^ajax_map_lookup/(?P<name>.+)/$", ajax_map_lookup, name="srs/ajax_map_lookup"),
    url(
        r"^ajax_playerrating_tbl_src/(?P<accountid>[\d-]+)/$",
        ajax_playerrating_tbl_src,
        name="srs/ajax_playerrating_tbl_src",
    ),
    url(
        r"^ajax_winloss_tbl_src/(?P<accountid>[\d-]+)/$",

        ajax_winloss_tbl_src,