コード例 #1
0
def test_create_card_populates_conjurations(client: TestClient,
                                            session: db.Session):
    """Creating a card adds its conjuration relationships"""
    # Verify that the pre-existing number of conjurations is what we expect
    assert session.query(CardConjuration).count() == 6
    admin, token = create_admin_token(session)
    # Create the conjuration first
    conj_data = copy(MINIMUM_VALID_CARD)
    conj_data["card_type"] = "Conjuration"
    conj_data["copies"] = 1
    conj_response = client.post("/v2/cards",
                                json=conj_data,
                                headers={"Authorization": f"Bearer {token}"})
    assert conj_response.status_code == status.HTTP_201_CREATED, conj_response.json(
    )
    # Then create the card that summons the conjuration
    card_data = copy(MINIMUM_VALID_CARD)
    card_data["name"] = "Summon Example Card"
    card_data[
        "text"] = "Place an [[Example Card]] conjuration on your battlefield."
    card_response = client.post("/v2/cards",
                                json=card_data,
                                headers={"Authorization": f"Bearer {token}"})
    assert card_response.status_code == status.HTTP_201_CREATED, card_response.json(
    )
    # Then verify that the conjuration is linked to the card
    assert session.query(CardConjuration).count() == 7
コード例 #2
0
ファイル: stream.py プロジェクト: onecrayon/api.ashes.live
def refresh_stream_for_entity(session: db.Session, entity_id: int,
                              entity_type: str, source_entity_id: int):
    """Creates or updates the Stream entry for the given entity

    **Please note:** this method does not commit the changes! You must flush the session in the
    invoking method.
    """
    if entity_type == "deck":
        entity = (session.query(Stream).filter(
            Stream.source_entity_id == source_entity_id,
            Stream.entity_type == "deck",
        ).first())
    else:
        entity = session.query(Stream).filter(
            Stream.entity_id == entity_id).first()
    if not entity:
        entity = Stream(
            entity_id=entity_id,
            entity_type=entity_type,
            source_entity_id=source_entity_id,
        )
    elif entity_type == "deck":
        # Decks are a special case; we update the Stream entity because the snapshots effectively
        # replace one another as far as most users are concerned
        entity.posted = datetime.utcnow()
        entity.entity_id = entity_id
    else:
        # Ignore comment edits
        return
    session.add(entity)
コード例 #3
0
def log_out(
        session: db.Session = Depends(get_session),
        jwt_payload: dict = Depends(get_auth_token),
        current_user: "******" = Depends(login_required),
):
    """Log a user out and revoke their JWT token's access rights.

    It's a good idea to invoke this whenever an authenticated user logs out, because tokens can otherwise be quite
    long-lived.
    """
    # Do some quick clean-up to keep our table lean and mean; deletes any tokens that expired more than 24 hours ago
    session.query(UserRevokedToken).filter(
        UserRevokedToken.expires < dt.datetime.utcnow() -
        dt.timedelta(days=1)).delete(synchronize_session=False)
    session.commit()
    # Then add our newly revoked token
    expires_at = dt.datetime.fromtimestamp(jwt_payload["exp"],
                                           tz=dt.timezone.utc)
    # No need to do `.get("jti")` here because a missing JTI would result in a credentials error in the dependencies
    revoked_hex = jwt_payload["jti"]
    revoked_uuid = uuid.UUID(hex=revoked_hex)
    revoked_token = UserRevokedToken(revoked_uuid=revoked_uuid,
                                     user_id=current_user.id,
                                     expires=expires_at)
    session.add(revoked_token)
    session.commit()
    return {"detail": "Token successfully revoked."}
コード例 #4
0
def save_collection(
        collection: List[str],
        session: db.Session = Depends(get_session),
        current_user: "******" = Depends(login_required),
):
    """Update the user's collection in place.

    PUT a list of release slugs to set them as the user's collection (e.g. `['master-set',
    'the-frostdale-giants']`.

    **This is not a patch!** You must pass the entire list of the user's collections every time.
    """
    # Clear out our existing releases
    session.query(UserRelease).filter(
        UserRelease.user_id == current_user.id).delete()
    session.commit()
    release_ids = ((session.query(Release.id).filter(
        Release.is_legacy.is_(False),
        Release.is_public.is_(True),
        Release.stub.in_(collection),
    ).all()) if collection else None)
    if release_ids:
        for row in release_ids:
            session.add(UserRelease(user_id=current_user.id,
                                    release_id=row.id))
        session.commit()
    query = get_releases_query(session=session, current_user=current_user)
    return query.all()
コード例 #5
0
def test_clone_deck(client: TestClient, session: db.Session, deck, user_token):
    """Can clone own deck"""
    user, token = user_token
    # Verify that we have three "decks" (original deck, private snapshot, public snapshot)
    assert session.query(Deck).filter(Deck.user_id == user.id).count() == 3
    response = client.get(
        f"/v2/decks/{deck.id}/clone",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_200_OK
    # Check that we now have two more decks than before: new deck, and source snapshot
    assert session.query(Deck).filter(Deck.user_id == user.id).count() == 5
コード例 #6
0
ファイル: deck.py プロジェクト: onecrayon/api.ashes.live
def deck_to_dict(session: db.Session,
                 deck: Deck,
                 include_comment_entity_id=False) -> dict:
    """Converts a Deck object into an output dict using as few queries as possible."""
    needed_cards = set()
    needed_cards.add(deck.phoenixborn_id)
    deck_cards = session.query(DeckCard).filter(
        DeckCard.deck_id == deck.id).all()
    for deck_card in deck_cards:
        needed_cards.add(deck_card.card_id)
    deck_dice = session.query(DeckDie).filter(DeckDie.deck_id == deck.id).all()
    # And finally we need to fetch all top-level conjurations
    card_id_to_conjurations = get_conjuration_mapping(session=session,
                                                      card_ids=needed_cards)
    # Now that we have root-level conjurations, we can gather all our cards and generate deck output
    cards = session.query(Card).filter(Card.id.in_(needed_cards)).all()
    card_id_to_card = {x.id: x for x in cards}
    deck_dict = generate_deck_dict(
        deck=deck,
        card_id_to_card=card_id_to_card,
        card_id_to_conjurations=card_id_to_conjurations,
        deck_cards=deck_cards,
        deck_dice=deck_dice,
    )
    deck_dict["description"] = deck.description
    deck_dict["is_public"] = deck.is_public
    deck_dict["is_snapshot"] = deck.is_snapshot
    if include_comment_entity_id:
        # This is an implicit SQL lookup, but it's going to require a lookup either way, so meh
        deck_dict["comments_entity_id"] = (deck.source.entity_id if
                                           deck.source_id else deck.entity_id)
    # If we are including first five information, grab that now
    first_five = []
    effect_costs = []
    tutor_map = {}
    # This is another implicit SQL lookup, but again it requires a lookup either way
    for selected_card in deck.selected_cards:
        card = card_id_to_card.get(selected_card.card_id)
        # This situation should theoretically never happen, but just in case...
        if not card:
            continue
        if selected_card.is_first_five:
            first_five.append(card.stub)
        if selected_card.is_paid_effect:
            effect_costs.append(card.stub)
        if selected_card.tutor_card_id:
            tutor_card = card_id_to_card.get(selected_card.tutor_card_id)
            if tutor_card:
                tutor_map[tutor_card.stub] = card.stub
    deck_dict["first_five"] = first_five
    deck_dict["effect_costs"] = effect_costs
    deck_dict["tutor_map"] = tutor_map
    return deck_dict
コード例 #7
0
def test_delete_public_snapshot(client: TestClient, session: db.Session,
                                user_token, deck):
    """Must properly clean up stream entries when deleting a public snapshot"""
    user, token = user_token
    snapshot = create_snapshot_for_deck(session, user, deck, is_public=True)
    assert session.query(Stream).count() == 1
    response = client.delete(f"/v2/decks/{snapshot.id}",
                             headers={"Authorization": f"Bearer {token}"})
    assert response.status_code == status.HTTP_204_NO_CONTENT
    assert session.query(Stream).count() == 0
    session.refresh(snapshot)
    assert snapshot.is_deleted == True
コード例 #8
0
def test_delete_latest_public_snapshot(client: TestClient, session: db.Session,
                                       user_token, deck):
    """Must properly revert to older snapshot in stream when deleting a public snapshot"""
    user, token = user_token
    snapshot1 = create_snapshot_for_deck(session, user, deck, is_public=True)
    snapshot2 = create_snapshot_for_deck(session, user, deck, is_public=True)
    assert session.query(Stream).count() == 1
    response = client.delete(f"/v2/decks/{snapshot2.id}",
                             headers={"Authorization": f"Bearer {token}"})
    assert response.status_code == status.HTTP_204_NO_CONTENT
    stream_entry = session.query(Stream).first()
    assert stream_entry.entity_id == snapshot1.entity_id
    session.refresh(snapshot2)
    assert snapshot2.is_deleted == True
コード例 #9
0
def get_phoenixborn_cards_dice(
    session: db.Session, release_stub: str = None
) -> Tuple[Card, List[dict], List[dict]]:
    """Returns the Phoenixborn and lists of cards/dice dicts suitable to create a deck

    Returns (phoenixborn, cards, dice)
    """
    release: Release = (
        session.query(Release).filter(Release.stub == release_stub).first()
        if release_stub
        else None
    )
    phoenixborn_query = session.query(Card).filter(Card.card_type == "Phoenixborn")
    if release:
        phoenixborn_query = phoenixborn_query.filter(Card.release_id == release.id)
    else:
        phoenixborn_query = phoenixborn_query.order_by(func.random())
    phoenixborn: Card = phoenixborn_query.first()
    if not phoenixborn:
        raise ValueError("No such test Phoenixborn!")
    unique_card: Card = (
        session.query(Card)
        .filter(
            Card.phoenixborn == phoenixborn.name,
            Card.card_type.notin_(CONJURATION_TYPES),
        )
        .first()
    )
    cards_query = session.query(Card).filter(
        Card.card_type.notin_(
            ("Conjuration", "Conjured Alteration Spell", "Phoenixborn")
        ),
        Card.phoenixborn.is_(None),
    )
    if release:
        cards_query = cards_query.filter(Card.release_id == release.id)
    else:
        cards_query = cards_query.order_by(func.random())
    deck_cards: List[Card] = cards_query.limit(9).all()
    card_dicts = [{"stub": x.stub, "count": 3} for x in deck_cards]
    card_dicts.append({"stub": unique_card.stub, "count": 3})
    dice_dicts = [
        {"name": "natural", "count": 5},
        {"name": "sympathy", "count": 3},
        {"name": "charm", "count": 2},
    ]

    return phoenixborn, card_dicts, dice_dicts
コード例 #10
0
def check_notification_state(i):
    while 1:
            session = Session()
            ins_opition = queue_notification.get(True)
            print "Greenlets %s got : %s" % (i,time.asctime()), " " , ins_opition
            sql = """
                SELECT result
                FROM cloud_result
                WHERE TIME = ( 
                SELECT MAX( TIME ) 
                FROM cloud_result ) 
                AND uuid
                IN (
                '%s'
                )
                """ % ins_opition['uuid']
            result = raw_sql(sql)
            # if result is empty, skip current loop.
            if not result:
                continue
            # analyst notification in another function
            ret = analyst_notification_result(result,ins_opition)
            print "Greenlets notification %s got : %s" % (i,time.asctime()) , ret
            if not ret:
                continue
            q = session.query(Instances).filter(Instances.uuid==ins_opition['uuid'])
            if q.all():
                q.update(
                    {Instances.notification_state:simplejson.dumps(ret)}
                )
                session.commit()
コード例 #11
0
ファイル: players.py プロジェクト: onecrayon/api.ashes.live
def create_player(
        token: UUID4,
        data: schema.UserRegistrationIn,
        session: db.Session = Depends(get_session),
        _=Depends(anonymous_required),
):
    """Create a new player using the token obtained by requesting an invite.

    Will fail if requested by an authenticated user.
    """
    invite = session.query(Invite).filter(Invite.uuid == token).first()
    if invite is None:
        raise NotFoundException(
            detail="Token not found. Please request a new invite.")
    user = create_user(
        session,
        invite.email,
        data.password,
        username=data.username,
        description=data.description,
        newsletter_opt_in=data.newsletter_opt_in,
    )
    session.delete(invite)
    session.commit()
    access_token = access_token_for_user(user)
    return {"access_token": access_token, "token_type": "bearer", "user": user}
コード例 #12
0
ファイル: players.py プロジェクト: onecrayon/api.ashes.live
def request_invite(
        data: schema.UserEmailIn,
        session: db.Session = Depends(get_session),
        _=Depends(anonymous_required),
):
    """Request an invite be sent to the given email.

    Will fail if requested by an authenticated user.
    """
    email = data.email.lower()
    user = session.query(User).filter(User.email == email).first()
    if user:
        raise APIException(detail="This email is already in use.", )
    invitation = get_invite_for_email(session, email)
    # Email the user
    if not send_message(
            recipient=invitation.email,
            template_id=settings.sendgrid_invite_template,
            data={
                "invite_token": str(invitation.uuid),
                "email": invitation.email,
            },
    ):
        if settings.debug:
            logger.debug(f"INVITE TOKEN FOR {email}: {invitation.uuid}")
        raise APIException(
            detail=
            "Unable to send invitation email; please report this to Skaak#0007 on Discord!"
        )
    return {
        "detail":
        "Your invitation has been sent! Please follow the link in your email to set your password."
    }
コード例 #13
0
ファイル: players.py プロジェクト: onecrayon/api.ashes.live
def get_user_data(badge: str, session: db.Session = Depends(get_session)):
    """Return public user information for any user."""
    user = (session.query(User).filter(User.badge == badge,
                                       User.is_banned.is_(False)).first())
    if not user:
        raise NotFoundException(detail="User not found.")
    return user
コード例 #14
0
def test_create_card_implicit_release(client: TestClient, session: db.Session):
    """Creating a card implicitly creates an unpublished release"""
    # Verify that the number of releases is what we expect
    release_query = (session.query(Release).filter(
        Release.is_legacy.is_(False)).order_by(Release.id.desc()))
    assert release_query.count() == 2
    admin, token = create_admin_token(session)
    response = client.post(
        "/v2/cards",
        json=MINIMUM_VALID_CARD,
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_201_CREATED, response.json()
    assert release_query.count() == 3
    release: Release = release_query.first()
    assert release.name == MINIMUM_VALID_CARD["release"]
    assert release.is_public == False
    # And verify we don't end up with multiple releases on subsequent cards
    card_data = copy(MINIMUM_VALID_CARD)
    card_data["name"] += " 2"
    response = client.post(
        "/v2/cards",
        json=card_data,
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_201_CREATED, response.json()
    assert release_query.count() == 3
コード例 #15
0
def test_register_user(client: TestClient, session: db.Session):
    """User is created and invite destroyed upon registration"""
    email = utils.generate_random_email()
    invite = get_invite_for_email(session, email)
    password = utils.generate_random_chars(10)
    response = client.post(
        f"/v2/players/new/{invite.uuid}",
        json={
            "username": "******",
            "password": password,
            "password_confirm": password
        },
    )
    assert response.status_code == status.HTTP_201_CREATED, response.json()
    assert session.query(Invite).filter(Invite.email == email).count() == 0
    assert session.query(User).filter(User.email == email).count() == 1
コード例 #16
0
def test_put_deck_tutor_map(client: TestClient, session: db.Session,
                            user_token):
    """Must properly handle both good and bogus cards within tutor map"""
    user, token = user_token
    valid_deck = _valid_deck_dict(session)
    valid_stubs = [x["stub"] for x in valid_deck["cards"]]
    bad_stub = (session.query(Card.stub).filter(
        Card.phoenixborn.is_(None),
        Card.card_type.notin_(CONJURATION_TYPES),
        Card.card_type != "Phoenixborn",
        Card.stub.notin_(valid_stubs),
    ).limit(1).scalar())
    valid_deck["tutor_map"] = {
        valid_stubs[0]: valid_stubs[1],
        bad_stub: valid_stubs[2],
        valid_stubs[3]: bad_stub,
    }
    response = client.put("/v2/decks",
                          json=valid_deck,
                          headers={"Authorization": f"Bearer {token}"})
    assert response.status_code == status.HTTP_200_OK
    data = response.json()
    assert bad_stub not in data["tutor_map"].keys()
    assert bad_stub not in data["tutor_map"].values()
    assert valid_stubs[0] in data["tutor_map"].keys()
    assert valid_stubs[1] in data["tutor_map"].values()
コード例 #17
0
def get_releases_query(session: db.Session,
                       current_user: UserType,
                       show_legacy=False):
    """Returns the query necessary to fetch a list of releases

    If a user is passed, then the releases will be tagged `is_mine` if in that user's collection.
    """
    if current_user.is_anonymous():
        query = session.query(Release.name, Release.stub, Release.is_legacy)
    else:
        query = session.query(
            Release.name,
            Release.stub,
            Release.is_legacy,
            db.case(
                [
                    (UserRelease.release_id == Release.id, True),
                ],
                else_=False,
            ).label("is_mine"),
        ).outerjoin(
            UserRelease,
            db.and_(
                UserRelease.release_id == Release.id,
                UserRelease.user_id == current_user.id,
            ),
        )
    query = query.filter(
        Release.is_legacy.is_(show_legacy),
        Release.is_public.is_(True),
    ).order_by(Release.id.asc())
    return query
コード例 #18
0
def log_in(
        form_data: OAuth2PasswordRequestForm = Depends(),
        session: db.Session = Depends(get_session),
        _=Depends(anonymous_required),
):
    """Log a user in and return a JWT authentication token to authenticate future requests.

    **Please note:** Only username and password are currently in use, and `username` must be the
    user's registered email.

    If you pass in `token:longterm` in the scopes, then you will be issued a long-lived token
    (defaults to one year before expiring).
    """
    email = form_data.username.lower()
    user = session.query(User).filter(User.email == email).first()
    if not user or not verify_password(form_data.password, user.password):
        raise CredentialsException(detail="Incorrect username or password", )
    if user.is_banned:
        raise BannedUserException()
    is_long_term = False
    for scope in form_data.scopes:
        if scope.lower() == "token:longterm":
            is_long_term = True
            break
    access_token = access_token_for_user(user, is_long_term=is_long_term)
    return {"access_token": access_token, "token_type": "bearer", "user": user}
コード例 #19
0
def test_invite_existing_user(client: TestClient, session: db.Session):
    """Requesting an invite for a registered emails throws an error"""
    user, _ = utils.create_user_token(session)
    response = client.post("/v2/players/new", json={"email": user.email})
    assert response.status_code == status.HTTP_400_BAD_REQUEST, respone.json()
    assert session.query(Invite).filter(
        Invite.email == user.email).count() == 0
コード例 #20
0
def request_password_reset(
        data: UserEmailIn,
        session: db.Session = Depends(get_session),
        _=Depends(anonymous_required),
):
    """Request a reset password link for the given email."""
    email = data.email.lower()
    user: User = session.query(User).filter(User.email == email).first()
    if not user:
        raise NotFoundException(detail="No account found for email.")
    if user.is_banned:
        raise BannedUserException()
    user.reset_uuid = uuid.uuid4()
    session.commit()
    if not send_message(
            recipient=user.email,
            template_id=settings.sendgrid_reset_template,
            data={
                "reset_token": str(user.reset_uuid),
                "email": user.email
            },
    ):
        if settings.debug:
            logger.debug(f"RESET TOKEN FOR {email}: {user.reset_uuid}")
        raise APIException(
            detail=
            "Unable to send password reset email; please contact Skaak#0007 on Discord."
        )
    return {
        "detail": "A link to reset your password has been sent to your email!"
    }
コード例 #21
0
ファイル: deck.py プロジェクト: onecrayon/api.ashes.live
def paginate_deck_listing(query: db.Query, session: db.Session,
                          request: Request, paging: PaginationOptions) -> dict:
    """Generates a paginated deck listing using as few queries as possible."""
    # Gather our paginated results
    output = paginated_results_for_query(query=query,
                                         paging=paging,
                                         url=str(request.url))
    # Parse through the decks so that we can load their cards en masse with a single query
    deck_ids = set()
    needed_cards = set()
    for deck_row in output["results"]:
        deck_ids.add(deck_row.id)
        # Ensure we lookup our Phoenixborn cards
        needed_cards.add(deck_row.phoenixborn_id)
    # Fetch and collate our dice information for all decks
    deck_dice = session.query(DeckDie).filter(
        DeckDie.deck_id.in_(deck_ids)).all()
    deck_id_to_dice = defaultdict(list)
    for deck_die in deck_dice:
        deck_id_to_dice[deck_die.deck_id].append(deck_die)
    # Now that we have all our basic deck information, look up the cards and quantities they include
    deck_cards = session.query(DeckCard).filter(
        DeckCard.deck_id.in_(deck_ids)).all()
    deck_id_to_deck_cards = defaultdict(list)
    for deck_card in deck_cards:
        needed_cards.add(deck_card.card_id)
        deck_id_to_deck_cards[deck_card.deck_id].append(deck_card)
    # And finally we need to fetch all top-level conjurations
    card_id_to_conjurations = get_conjuration_mapping(session=session,
                                                      card_ids=needed_cards)
    # Now that we have root-level conjurations, we can gather all our cards and setup our decks
    cards = session.query(Card).filter(Card.id.in_(needed_cards)).all()
    card_id_to_card = {x.id: x for x in cards}
    deck_output = []
    for deck in output["results"]:
        deck_output.append(
            generate_deck_dict(
                deck=deck,
                card_id_to_card=card_id_to_card,
                card_id_to_conjurations=card_id_to_conjurations,
                deck_cards=deck_id_to_deck_cards[deck.id],
                deck_dice=deck_id_to_dice.get(deck.id),
            ))
    output["results"] = deck_output
    return output
コード例 #22
0
def test_delete_deck_no_snapshots(client: TestClient, session: db.Session,
                                  user_token, deck):
    """Must actually delete the deck if it has no snapshots"""
    user, token = user_token
    old_id = deck.id
    response = client.delete(f"/v2/decks/{deck.id}",
                             headers={"Authorization": f"Bearer {token}"})
    assert response.status_code == status.HTTP_204_NO_CONTENT
    assert session.query(Deck).filter(Deck.id == old_id).first() is None
コード例 #23
0
def test_invite_requests_incremented(client: TestClient, session: db.Session,
                                     monkeypatch):
    """Requesting an invite multiple times must increment the requests counter"""
    def _always_true(*args, **kwargs):
        return True

    # Just patch the whole send_email method; its behavior is tested elsewhere
    monkeypatch.setattr(api.views.players, "send_message", _always_true)
    fake_email = utils.generate_random_email()
    response = client.post("/v2/players/new", json={"email": fake_email})
    assert response.status_code == status.HTTP_201_CREATED, response.json()
    assert (session.query(
        Invite.requests).filter(Invite.email == fake_email).scalar() == 1)
    # Request a second time
    response = client.post("/v2/players/new", json={"email": fake_email})
    assert response.status_code == status.HTTP_201_CREATED, response.json()
    assert (session.query(
        Invite.requests).filter(Invite.email == fake_email).scalar() == 2)
コード例 #24
0
ファイル: deck.py プロジェクト: onecrayon/api.ashes.live
def get_decks_query(
    session: db.Session,
    show_legacy=False,
    is_public=False,
    order: PaginationOrderOptions = PaginationOrderOptions.desc,
    # Filtering options
    q: Optional[str] = None,
    phoenixborn: Optional[List[str]] = None,
    cards: Optional[List[str]] = None,
    players: Optional[List[str]] = None,
    show_preconstructed=False,
) -> db.Query:
    query = session.query(Deck).filter(Deck.is_legacy.is_(show_legacy),
                                       Deck.is_deleted.is_(False))
    if show_preconstructed:
        query = query.filter(Deck.is_preconstructed.is_(True))
    if is_public:
        deck_comp = db.aliased(Deck)
        query = query.outerjoin(
            deck_comp,
            db.and_(
                Deck.source_id == deck_comp.source_id,
                deck_comp.is_snapshot.is_(True),
                deck_comp.is_public.is_(True),
                deck_comp.is_deleted.is_(False),
                db.or_(
                    Deck.created < deck_comp.created,
                    db.and_(Deck.created == deck_comp.created,
                            Deck.id < deck_comp.id),
                ),
            ),
        ).filter(deck_comp.id.is_(None), Deck.is_snapshot.is_(True),
                 Deck.is_public.is_(True))
    else:
        query = query.filter(Deck.is_snapshot.is_(False))
    if q and q.strip():
        query = query.filter(
            db.func.to_tsvector("english", db.cast(Deck.title, db.Text)).match(
                to_prefixed_tsquery(q)))
    # Filter by Phoenixborn stubs (this is always an OR comparison between Phoenixborn)
    if phoenixborn:
        query = query.join(Card, Card.id == Deck.phoenixborn_id).filter(
            Card.stub.in_(phoenixborn))
    # Filter by cards (this is always an OR comparison between cards)
    if cards:
        card_table = db.aliased(Card)
        query = (query.join(DeckCard, DeckCard.deck_id == Deck.id).join(
            card_table, card_table.id == DeckCard.card_id).filter(
                card_table.stub.in_(cards)))
    # Filter by player badge, and always ensure that we eagerly load the user object
    if players:
        query = (query.join(User, User.id == Deck.user_id).filter(
            User.badge.in_(players)).options(db.contains_eager(Deck.user)))
    else:
        query = query.options(db.joinedload(Deck.user))
    return query.order_by(getattr(Deck.created, order)())
コード例 #25
0
ファイル: deck.py プロジェクト: onecrayon/api.ashes.live
def get_conjuration_mapping(session: db.Session, card_ids: Set[int]) -> dict:
    """Gathers top-level conjurations into a mapping keyed off the root card ID"""
    conjuration_results = (session.query(
        Card, CardConjuration.card_id.label("root_card")).join(
            CardConjuration, Card.id == CardConjuration.conjuration_id).filter(
                CardConjuration.card_id.in_(card_ids)).all())
    card_id_to_conjurations = defaultdict(list)
    for result in conjuration_results:
        card_id_to_conjurations[result.root_card].append(result.Card)
    return card_id_to_conjurations
コード例 #26
0
ファイル: test_auth.py プロジェクト: onecrayon/api.ashes.live
def test_revoke_token_cleanup(client: TestClient, session: db.Session):
    """Revoking a token must clean up old revoked tokens"""

    def revoke_token(time):
        with freeze_time(time):
            user, token = utils.create_user_token(session)
            response = client.delete(
                "/v2/token", headers={"Authorization": f"Bearer {token}"}
            )
            assert response.status_code == status.HTTP_200_OK, response.json()

    now = datetime.utcnow()
    # Revoke a token 2 days ago
    one_day = now - timedelta(days=2)
    revoke_token(one_day)
    assert session.query(UserRevokedToken).count() == 1
    # Revoke a token now, so that the first token should get purged
    revoke_token(now)
    assert session.query(UserRevokedToken).count() == 1
コード例 #27
0
def test_delete_root_deck(client: TestClient, session: db.Session, user_token):
    """Must delete stream entry and mark all snapshots deleted when deleting root deck"""
    user, token = user_token
    deck = create_deck_for_user(session, user)
    private_snapshot = create_snapshot_for_deck(session, user, deck)
    public_snapshot = create_snapshot_for_deck(session,
                                               user,
                                               deck,
                                               is_public=True)
    assert session.query(Stream).count() == 1
    response = client.delete(f"/v2/decks/{deck.id}",
                             headers={"Authorization": f"Bearer {token}"})
    assert response.status_code == status.HTTP_204_NO_CONTENT
    assert session.query(Stream).count() == 0
    session.refresh(deck)
    session.refresh(private_snapshot)
    session.refresh(public_snapshot)
    assert deck.is_deleted == True
    assert private_snapshot.is_deleted == True
    assert public_snapshot.is_deleted == True
コード例 #28
0
ファイル: test_auth.py プロジェクト: onecrayon/api.ashes.live
def test_anonymous_required_authenticated_user(client: TestClient, session: db.Session):
    """Authenticated users cannot access endpoints that require anonymity"""
    _, token = utils.create_user_token(session)
    fake_email = utils.generate_random_email()
    response = client.post(
        "/v2/players/new",
        json={"email": fake_email},
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_401_UNAUTHORIZED, response.json()
    assert session.query(Invite).filter(Invite.email == fake_email).count() == 0
コード例 #29
0
def test_clone_public_snapshot(client: TestClient, session: db.Session,
                               user2_token, public_snapshot):
    """Can clone a public snapshot from another user"""
    user, token = user2_token
    response = client.get(
        f"/v2/decks/{public_snapshot.id}/clone",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_200_OK
    # One is the new deck object, and the other is the source ID snapshot
    assert session.query(Deck).filter(Deck.user_id == user.id).count() == 2
コード例 #30
0
def test_clone_private_shared_deck(client: TestClient, session: db.Session,
                                   snapshot, user2_token):
    """Can clone a private shared deck with direct_share_uuid"""
    user, token = user2_token
    response = client.get(
        f"/v2/decks/{snapshot.id}/clone",
        params={"direct_share_uuid": str(snapshot.direct_share_uuid)},
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_200_OK, response.json()
    # One is the new deck object, and the other is the source ID snapshot
    assert session.query(Deck).filter(Deck.user_id == user.id).count() == 2
コード例 #31
0
def test_post_snapshot(client: TestClient, session: db.Session, user_token,
                       deck):
    """Posting a snapshot must inherit the old deck's details"""
    user, token = user_token
    response = client.post(
        f"/v2/decks/{deck.id}/snapshot",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == status.HTTP_201_CREATED
    snapshot = session.query(Deck).order_by(Deck.id.desc()).first()
    assert snapshot.title == deck.title
    assert snapshot.description == deck.description
コード例 #32
0
def check_moniting_state_icmp(i):
    while 1:
        #try:
        session = Session()
        ins = queue_moniting.get(True)
        print "Greenlets %s got : %s" % (i,time.asctime()), " " , ins
        instance_result = dict()
        moniting_state = eval(ins['moniting_state'])
        ipaddress = eval(ins['ipaddress'])
        ping = moniting_state['ping']
        arp = moniting_state['arp']
        tcp = moniting_state['tcp']
        udp = moniting_state['udp']
        if ipaddress:
            instance_result['uuid'] = ins['uuid']
            for ip in ipaddress:
                instance_result[ip] = dict()
                if ping:
                    instance_result[ip]['ping'] = 1 if icmp_checker_gevent.check_icmp(ip) == True else 0
                #if arp:
                #    instance_result[ip]['arp'] = 1 if arp_checker_gevent.check_arp(ip) == True else 0
                #if tcp:
                #    instance_result[ip]['tcp'] = dict()
                #    if isinstance(tcp,unicode):
                #        # if tcp is unicode string, means that's only one port.
                #        port = tcp
                #        instance_result[ip]['tcp'][port] = 1 if tcp_checker_gevent.check_tcp(ip,int(port)) == True else 0
                #    else:
                #        for port in tcp:
                #            instance_result[ip]['tcp'][port] = 1 if tcp_checker_gevent.check_tcp(ip,int(port)) == True else 0
                ##if udp:
                #    instance_result[ip]['udp'] = dict()
                #    if isinstance(udp,unicode):
                #        # if tcp is unicode string, means that's only one port.
                #        port = udp
                #        instance_result[ip]['udp'][port] = 1 if udp_checker.checker_udp(ip,int(port)) == True else 0
                #    else:
                #        for port in udp:
                #            instance_result[ip]['udp'][port] = 1 if udp_checker.checker_udp(ip,int(port)) == True else 0
        
        print "Greenlets moniting %s got : %s" % (i,time.asctime()) , instance_result
        # send notification to user, use http or sms
        send_notification(instance_result,'moniting')
        # save last notification, used in next time
        save_one_notification(instance_result,'moniting')
        
        q = session.query(Instances).filter(Instances.uuid==ins['uuid'])
        if q.all():
            q.update(
                {Instances.moniting_state:simplejson.dumps(instance_result)}
            )
            session.commit()
コード例 #33
0
class check_notification_state(threading.Thread):
    """
    check moniting state for instance
    """
    def __init__(self):
        super(check_notification_state,self).__init__()
        self.daemon = True
        self.session = Session()
        
    
    def run(self):
        while 1:
                ins_opition = queue_notification.get(True)
                sql = """
                    SELECT result
                    FROM cloud_result
                    WHERE TIME = (
                    SELECT MAX( TIME ) 
                    FROM cloud_result ) 
                    AND uuid
                    IN (
                    '%s'
                    )
                    """ % ins_opition['uuid']
                result = raw_sql(sql)
                # if result is empty, skip current loop.
                if not result:
                    continue
                # analyst notification in another function
                ret = analyst_notification_result(result,ins_opition)
                if not ret:
                    continue
                q = self.session.query(Instances).filter(Instances.uuid==ins_opition['uuid'])
                if q.all():
                    q.update(
                        {Instances.notification_state:simplejson.dumps(ret)}
                    )
                    self.session.commit()
コード例 #34
0
class check_moniting_state(threading.Thread):
    """
    check moniting state for instance
    """
    def __init__(self):
        super(check_moniting_state,self).__init__()
        self.daemon = True
        self.session = Session()
        
    
    def run(self):
        while 1:
            #try:
            ins = queue_moniting.get(True)
            instance_result = dict()
            moniting_state = eval(ins['moniting_state'])
            ipaddress = eval(ins['ipaddress'])
            ping = moniting_state['ping']
            arp = moniting_state['arp']
            tcp = moniting_state['tcp']
            udp = moniting_state['udp']
            if ipaddress:
                instance_result['uuid'] = ins['uuid']
                for ip in ipaddress:
                    instance_result[ip] = dict()
                    if ping:
                        instance_result[ip]['ping'] = 1 if icmp_checker.check_icmp(ip) == True else 0
                    if arp:
                        instance_result[ip]['arp'] = 1 if arp_checker.check_arp(ip) == True else 0
                    if tcp:
                        instance_result[ip]['tcp'] = dict()
                        if isinstance(tcp,unicode):
                            # if tcp is unicode string, means that's only one port.
                            port = tcp
                            instance_result[ip]['tcp'][port] = 1 if tcp_checker.check_tcp(ip,int(port)) == True else 0
                        else:
                            for port in tcp:
                                instance_result[ip]['tcp'][port] = 1 if tcp_checker.check_tcp(ip,int(port)) == True else 0
                    if udp:
                        instance_result[ip]['udp'] = dict()
                        if isinstance(udp,unicode):
                            # if tcp is unicode string, means that's only one port.
                            port = udp
                            instance_result[ip]['udp'][port] = 1 if udp_checker.checker_udp(ip,int(port)) == True else 0
                        else:
                            for port in udp:
                                instance_result[ip]['udp'][port] = 1 if udp_checker.checker_udp(ip,int(port)) == True else 0
            # send notification to user, use http or sms
            send_notification(instance_result,'moniting')
            # save last notification, used in next time
            save_one_notification(instance_result,'moniting')
            
            q = self.session.query(Instances).filter(Instances.uuid==ins['uuid'])
            if q.all():
                q.update(
                    {Instances.moniting_state:simplejson.dumps(instance_result)}
                )
                self.session.commit()
            #except:
            #    pass
            
            # dont forget to close session at the end
            self.session.close()