def test_invites_list_cache_clear(app, authed_client): """Sending an invite should clear the cache key for a user's list of invites.""" app.config['REQUIRE_INVITE_CODE'] = True add_permissions(app, 'invites_send') Invite.from_inviter(1) # Cache it authed_client.post( '/invites', data=json.dumps({'email': '*****@*****.**'}) ) sent_invites = Invite.from_inviter(1, include_dead=True) assert len(sent_invites) == 4
def invites_view(user: User, used: bool, include_dead: bool) -> flask.Response: """ View sent invites. If a user_id is specified, only invites sent by that user will be returned, otherwise only your invites are returned. If requester has the ``invites_view_others`` permission, they can view sent invites of another user. .. :quickref: Invite; View multiple invites. **Example response**: .. parsed-literal:: { "status": "success", "response": [ "<Invite>", "<Invite>" ] } :query boolean used: (Optional) Whether or not to only show used invites (overrides ``include_dead``) :query boolean include_dead: (Optional) Whether or not to include expired invites :>json list response: A list of invites :statuscode 200: View successful :statuscode 403: User does not have permission to view user's invites """ invites = Invite.from_inviter(user.id, include_dead=include_dead, used=used) return flask.jsonify(invites)
def ValInviteCode(code: Optional[str]) -> None: """ Check an invite code against existing invite codes; Raises an APIException if the code isn't valid. :param code: Invite code to check and verify :return: An invite code or, if site is open registration, ``None`` :raises APIException: The invite code cannot be used """ if not app.config['REQUIRE_INVITE_CODE']: return if code is not None and (not isinstance(code, str) or len(code) != 24): raise APIException('Invite code must be a 24 character string.') invite = Invite.from_pk(code) if invite and not invite.invitee_id: time_since_usage = (datetime.utcnow().replace(tzinfo=pytz.utc) - invite.time_sent) if time_since_usage.total_seconds() < app.config['INVITE_LIFETIME']: return if code: raise APIException(f'{code} is not a valid invite code.') raise APIException('An invite code is required for registration.')
def test_revoke_invite(app, authed_client, code, expected, invites): """Revoking an invite should work only for active invites.""" add_permissions(app, 'invites_revoke') response = authed_client.delete(f'/invites/{code}') user = User.from_pk(1) check_json_response(response, expected) assert user.invites == invites if 'expired' in expected and expected['expired'] is True: invite = Invite.from_pk(code, include_dead=True) assert invite.expired is True
def invite_user(email: str): """ Sends an invite to the provided email address. Requires the ``invites_send`` permission. If the site is open registration, this endpoint will raise a 400 Exception. .. :quickref: Invite; Send an invite. **Example request**: .. parsed-literal:: POST /invites/an-invite-code HTTP/1.1 { "email": "*****@*****.**" } **Example response**: .. parsed-literal:: { "status": "success", "response": "<Invite>" } :<json string email: E-mail to send the invite to :statuscode 200: Successfully sent invite :statuscode 400: Unable to send invites or incorrect email :statuscode 403: Unauthorized to send invites """ if not app.config['REQUIRE_INVITE_CODE']: raise APIException( 'An invite code is not required to register, so invites have been disabled.' ) if not flask.g.user.invites: raise APIException('You do not have an invite to send.') invite = Invite.new(inviter_id=flask.g.user.id, email=email, ip=flask.request.remote_addr) flask.g.user.invites -= 1 db.session.commit() return flask.jsonify(invite)
def view_invite(code: str) -> flask.Response: """ View the details of an invite. Requires the ``invites_view`` permission. Requires the ``invites_view_others`` permission to view another user's invites. .. :quickref: Invite; View an active invite. **Example request**: .. parsed-literal:: GET /invite HTTP/1.1 { "code": "an-invite-code" } **Example response**: .. parsed-literal:: HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "status": "success", "response": "<Invite>" } :statuscode 200: View successful :statuscode 404: Invite does not exist or user cannot view invite """ return flask.jsonify( Invite.from_pk( code, include_dead=True, _404=True, asrt=InvitePermissions.VIEW_OTHERS, ))
def revoke_invite(code: str) -> flask.Response: """ Revokes an active invite code, preventing it from being used. The invite is returned to the user's account. Requires the ``invites_revoke`` permission to revoke one's own sent invite, and the ``invites_revoke_others`` permission to revoke another user's invites. .. :quickref: Invite; Revoke an active invite. **Example request**: .. parsed-literal:: DELETE /invite HTTP/1.1 { "id": "an-invite-code" } **Example response**: .. parsed-literal:: { "status": "success", "response": "<Invite>" } :statuscode 200: Revocation successful :statuscode 403: Unauthorized to revoke invites :statuscode 404: Invite does not exist or user cannot view invite """ invite = Invite.from_pk(code, _404=True, asrt=InvitePermissions.REVOKE_OTHERS) invite.expired = True invite.inviter.invites += 1 db.session.commit() return flask.jsonify(invite)