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
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)
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."}
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()
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
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
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
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
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
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()
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}
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." }
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
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
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
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()
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
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}
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
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!" }
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
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
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)
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)())
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
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
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
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
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
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
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
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()
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()
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()