Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
 into player-compare-playlist
  • Loading branch information
Sciguymjm committed Oct 26, 2018
2 parents 37adcdb + 00b0385 commit bdc137a
Show file tree
Hide file tree
Showing 60 changed files with 1,422 additions and 62 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- `pip3 install -r requirements.txt`
- Install and run Redis with default port + settings (Windows is included, [Ubuntu](https://redis.io/topics/quickstart))
- Install postgreSQL ([Windows](https://www.enterprisedb.com/thank-you-downloading-postgresql?anid=1255928), [Ubuntu](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-16-04), [Mac](https://stackoverflow.com/a/35308200/2187510))
- If only for local development [change the password in Unbuntu](https://blog.2ndquadrant.com/how-to-safely-change-the-postgres-user-password-via-psql/) to `postgres`
- If only for local development [change the password in Ubuntu](https://blog.2ndquadrant.com/how-to-safely-change-the-postgres-user-password-via-psql/) to `postgres`
- Ensure you have the latest LTS version of node and npm installed
- Run `cd webapp`, `npm install`

Expand Down
5 changes: 5 additions & 0 deletions backend/blueprints/spa_api/errors/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ def __init__(self, missing_params: List[str]):
joined_missing_params = " and ".join(missing_params)
message = f'Query parameter{conditional_s} {joined_missing_params} are required.'
super().__init__(self.status_code, message)


class TagNotFound(CalculatedError):
status_code = 404
message = "Tag not found"
4 changes: 4 additions & 0 deletions backend/blueprints/spa_api/service_layers/player/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def create_from_id(id_: str) -> 'Player':
try:
steam_profile = get_steam_profile_or_random_response(id_)['response']['players'][0]
except TypeError:
if len(names_and_counts) > 0:
return Player(id_=id_, name=names_and_counts[0][0], past_names=names_and_counts, profile_link="",
avatar_link="/psynet.jpg" if not id_.startswith(
'b') else "/ai.jpg")
raise PlayerNotFound
session.close()
return Player(id_=id_, name=steam_profile['personaname'], past_names=names_and_counts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ class PlayerStatsChart:
@staticmethod
def create_from_id(id_: str) -> List[OutputChartData]:
session = current_app.config['db']()
wrapped_player_games = wrapper.get_chart_stats_for_player(session, id_)
try:
wrapped_player_games = wrapper.get_chart_stats_for_player(session, id_)
except Exception as e:
session.close()
raise e
session.close()
return wrapper.wrap_chart_stats(wrapped_player_games, player_stats_metadata)

Expand Down
8 changes: 7 additions & 1 deletion backend/blueprints/spa_api/service_layers/replay/replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from backend.database.objects import Game, PlayerGame
from data.constants.playlist import get_playlist
from .tag import Tag
from .replay_player import ReplayPlayer
from ..utils import sort_player_games_by_team_then_id
from ...errors.errors import ReplayNotFound
Expand All @@ -22,13 +23,14 @@ def create_from_game(game: Game):
class Replay:
def __init__(self, id_: str, name: str, date: str,
game_mode: str, game_score: GameScore,
players: List[ReplayPlayer]):
players: List[ReplayPlayer], tags: List[Tag]):
self.id = id_
self.name = name
self.date = date
self.gameMode = game_mode
self.gameScore = game_score.__dict__
self.players = [player.__dict__ for player in players]
self.tags = [tag.__dict__ for tag in tags]

@staticmethod
def create_from_id(id_: str) -> 'Replay':
Expand All @@ -52,5 +54,9 @@ def create_from_game(game: Game) -> 'Replay':
ReplayPlayer.create_from_player_game(player_game)
for player_game in sort_player_games_by_team_then_id(
cast(List[PlayerGame], game.playergames))
],
tags=[
Tag.create_from_dbtag(tag)
for tag in game.tags
]
)
84 changes: 84 additions & 0 deletions backend/blueprints/spa_api/service_layers/replay/tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from typing import List

from flask import g, current_app

from ...errors.errors import CalculatedError, TagNotFound
from backend.database.objects import Tag as DBTag
from backend.database.wrapper.tag_wrapper import TagWrapper, DBTagNotFound


class Tag:
def __init__(self, name: str, owner: str):
self.name = name
self.ownerId = owner

@staticmethod
def create_from_dbtag(tag: DBTag):
return Tag(tag.name, tag.owner)

@staticmethod
def create(name: str) -> 'Tag':
session = current_app.config['db']()

# Check if tag exists
try:
dbtag = TagWrapper.get_tag(g.user.platformid, name, session)
tag = Tag.create_from_dbtag(dbtag)
session.close()
return tag
except DBTagNotFound:
pass
dbtag = TagWrapper.create_tag(session, g.user.platformid, name)
tag = Tag.create_from_dbtag(dbtag)
session.close()
return tag

@staticmethod
def rename(current_name: str, new_name: str) -> 'Tag':
session = current_app.config['db']()

# Check if name already exists
try:
TagWrapper.get_tag(g.user.platformid, new_name, session)
session.close()
raise CalculatedError(409, f"Tag with name {new_name} already exists.")
except DBTagNotFound:
pass

try:
dbtag = TagWrapper.rename_tag(session, g.user.platformid, current_name, new_name)
except DBTagNotFound:
session.close()
raise TagNotFound()
tag = Tag.create_from_dbtag(dbtag)
session.close()
return tag

@staticmethod
def delete(name: str) -> None:
try:
TagWrapper.delete_tag(g.user.platformid, name)
except DBTagNotFound:
raise TagNotFound()

@staticmethod
def get_all() -> List['Tag']:
session = current_app.config['db']()
dbtags = TagWrapper.get_tags(session, g.user.platformid)
tags = [Tag.create_from_dbtag(dbtag) for dbtag in dbtags]
session.close()
return tags

@staticmethod
def add_tag_to_game(name: str, replay_id: str) -> None:
try:
TagWrapper.add_tag_to_game(replay_id, g.user.platformid, name)
except DBTagNotFound:
raise TagNotFound()

@staticmethod
def remove_tag_from_game(name: str, replay_id: str) -> None:
try:
TagWrapper.remove_tag_from_game(replay_id, g.user.platformid, name)
except DBTagNotFound:
raise TagNotFound()
57 changes: 53 additions & 4 deletions backend/blueprints/spa_api/spa_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
import shutil
import uuid

import pandas as pd
from carball.analysis.utils.proto_manager import ProtobufManager
from flask import jsonify, Blueprint, current_app, request, send_from_directory, send_file
from flask import jsonify, Blueprint, current_app, request, send_from_directory
from werkzeug.utils import secure_filename

from backend.blueprints.spa_api.service_layers.replay.basic_stats import PlayerStatsChart, TeamStatsChart
from backend.blueprints.steam import get_vanity_to_steam_id_or_random_response, steam_id_to_profile
from backend.database.objects import Game
from backend.database.utils.utils import add_objs_to_db, convert_pickle_to_db
Expand All @@ -21,7 +19,6 @@
from backend.tasks import celery_tasks
from backend.tasks.utils import get_queue_length
from .errors.errors import CalculatedError, MissingQueryParams
from .query_params_handler import QueryParam, convert_to_datetime, get_query_params, convert_to_enum
from .service_layers.global_stats import GlobalStatsGraph
from .service_layers.logged_in_user import LoggedInUser
from .service_layers.player.play_style import PlayStyleResponse
Expand All @@ -30,10 +27,15 @@
from .service_layers.player.player_profile_stats import PlayerProfileStats
from .service_layers.player.player_ranks import PlayerRanks
from .service_layers.queue_status import QueueStatus
from .service_layers.replay.basic_stats import PlayerStatsChart, TeamStatsChart
from .service_layers.replay.groups import ReplayGroupChartData
from .service_layers.replay.match_history import MatchHistory
from .service_layers.replay.replay import Replay
from .service_layers.replay.replay_positions import ReplayPositions
from .service_layers.replay.tag import Tag
from .utils.decorators import require_user
from .utils.query_params_handler import QueryParam, convert_to_datetime, get_query_params, \
convert_to_enum

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -340,6 +342,53 @@ def api_upload_proto():
return jsonify({'Success': True})


### TAG

@require_user
@bp.route('/tag/<name>', methods=["PUT"])
def api_create_tag(name: str):
tag = Tag.create(name)
return better_jsonify(tag), 201


@require_user
@bp.route('/tag/<current_name>', methods=["PATCH"])
def api_rename_tag(current_name: str):
accepted_query_params = [QueryParam(name='new_name')]
query_params = get_query_params(accepted_query_params, request)

tag = Tag.rename(current_name, query_params['new_name'])
return better_jsonify(tag), 200


@require_user
@bp.route('/tag/<name>', methods=['DELETE'])
def api_delete_tag(name: str):
Tag.delete(name)
return '', 204


@require_user
@bp.route('/tag')
def api_get_tags():
tags = Tag.get_all()
return better_jsonify(tags)


@require_user
@bp.route('/tag/<name>/replay/<id_>', methods=["PUT"])
def api_add_tag_to_game(name: str, id_: str):
Tag.add_tag_to_game(name, id_)
return '', 204


@require_user
@bp.route('/tag/<name>/replay/<id_>', methods=["DELETE"])
def api_remove_tag_from_game(name: str, id_: str):
Tag.remove_tag_from_game(name, id_)
return '', 204


@bp.errorhandler(CalculatedError)
def api_handle_error(error: CalculatedError):
response = jsonify(error.to_dict())
Expand Down
Empty file.
9 changes: 9 additions & 0 deletions backend/blueprints/spa_api/utils/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ..errors.errors import CalculatedError


def require_user(func):
def wrapper_require_user(*args, **kwargs):
if g.user is None:
raise CalculatedError(404, "User is not logged in.")
func(*args, **kwargs)
return wrapper_require_user
20 changes: 19 additions & 1 deletion backend/database/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import datetime
import enum

from sqlalchemy import Column, Integer, String, Boolean, Float, ForeignKey, DateTime, Enum
from sqlalchemy import Column, Integer, String, Boolean, Float, ForeignKey, DateTime, Enum, Table, UniqueConstraint
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, validates
Expand Down Expand Up @@ -226,6 +226,8 @@ class Game(DBObjectBase):
team1possession = Column(Float)
frames = Column(Integer)

tags = relationship('Tag', secondary='game_tags', back_populates='games')

# metadata
version = Column(Integer)
length = Column(Float, default=300.0)
Expand All @@ -251,6 +253,7 @@ class Player(DBObjectBase):
ranks = Column(postgresql.ARRAY(Integer, dimensions=1)) # foreign key
games = relationship('PlayerGame')
groups = Column(postgresql.ARRAY(Integer, dimensions=1), default=[])
owned_tags = relationship('Tag')

@validates('platformid')
def validate_code(self, key, value):
Expand Down Expand Up @@ -301,3 +304,18 @@ class TeamStat(DBObjectBase):
time_in_attacking_third = Column(Float)
time_behind_ball = Column(Float)
time_in_front_ball = Column(Float)


class Tag(DBObjectBase):
__tablename__ = 'tags'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(40))
owner = Column(String(40), ForeignKey('players.platformid'), index=True)
games = relationship('Game', secondary='game_tags', back_populates='tags')
__table_args_ = (UniqueConstraint(name, owner, name='unique_names'))


class GameTag(DBObjectBase):
__tablename__ = 'game_tags'
game_id = Column(String(40), ForeignKey('games.hash'), primary_key=True)
tag_id = Column(Integer, ForeignKey('tags.id'), primary_key=True)
Loading

0 comments on commit bdc137a

Please sign in to comment.