mirror of
https://github.com/GSA/notifications-api.git
synced 2026-06-21 05:30:55 -04:00
Merge pull request #97 from alphagov/invite-user
[WIP] added endpoint and dao to create invites for users.
This commit is contained in:
@@ -45,6 +45,7 @@ def create_app():
|
||||
from app.status.healthcheck import status as status_blueprint
|
||||
from app.job.rest import job as job_blueprint
|
||||
from app.notifications.rest import notifications as notifications_blueprint
|
||||
from app.invite.rest import invite as invite_blueprint
|
||||
|
||||
application.register_blueprint(service_blueprint, url_prefix='/service')
|
||||
application.register_blueprint(user_blueprint, url_prefix='/user')
|
||||
@@ -52,6 +53,7 @@ def create_app():
|
||||
application.register_blueprint(status_blueprint, url_prefix='/status')
|
||||
application.register_blueprint(notifications_blueprint, url_prefix='/notifications')
|
||||
application.register_blueprint(job_blueprint)
|
||||
application.register_blueprint(invite_blueprint)
|
||||
|
||||
return application
|
||||
|
||||
|
||||
6
app/dao/invited_user_dao.py
Normal file
6
app/dao/invited_user_dao.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from app import db
|
||||
|
||||
|
||||
def save_invited_user(invited_user):
|
||||
db.session.add(invited_user)
|
||||
db.session.commit()
|
||||
0
app/invite/__init__.py
Normal file
0
app/invite/__init__.py
Normal file
24
app/invite/rest.py
Normal file
24
app/invite/rest.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from flask import (
|
||||
Blueprint,
|
||||
request,
|
||||
jsonify
|
||||
)
|
||||
|
||||
from app.dao.invited_user_dao import save_invited_user
|
||||
from app.schemas import invited_user_schema
|
||||
|
||||
invite = Blueprint('invite', __name__, url_prefix='/service/<service_id>/invite')
|
||||
|
||||
from app.errors import register_errors
|
||||
register_errors(invite)
|
||||
|
||||
|
||||
@invite.route('', methods=['POST'])
|
||||
def create_invite_user(service_id):
|
||||
invited_user, errors = invited_user_schema.load(request.get_json())
|
||||
if errors:
|
||||
return jsonify(result="error", message=errors), 400
|
||||
|
||||
save_invited_user(invited_user)
|
||||
|
||||
return jsonify(data=invited_user_schema.dump(invited_user).data), 201
|
||||
@@ -239,7 +239,6 @@ class InvitedUser(db.Model):
|
||||
from_user = db.relationship('User')
|
||||
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False)
|
||||
service = db.relationship('Service')
|
||||
_token = db.Column(db.String, nullable=False)
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
index=False,
|
||||
@@ -247,15 +246,4 @@ class InvitedUser(db.Model):
|
||||
nullable=False,
|
||||
default=datetime.datetime.now)
|
||||
status = db.Column(
|
||||
db.Enum(*INVITED_USER_STATUS_TYPES, name='invited_users_status_types'), nullable=False, default='invited')
|
||||
|
||||
@property
|
||||
def token(self):
|
||||
raise AttributeError("Token not readable")
|
||||
|
||||
@token.setter
|
||||
def token(self, token):
|
||||
self._token = hashpw(token)
|
||||
|
||||
def check_token(self, token):
|
||||
return check_hash(token, self._token)
|
||||
db.Enum(*INVITED_USER_STATUS_TYPES, name='invited_users_status_types'), nullable=False, default='pending')
|
||||
|
||||
@@ -118,6 +118,16 @@ class NotificationStatusSchema(BaseSchema):
|
||||
model = models.Notification
|
||||
|
||||
|
||||
class InvitedUserSchema(BaseSchema):
|
||||
class Meta:
|
||||
model = models.InvitedUser
|
||||
|
||||
@validates('email_address')
|
||||
def validate_to(self, value):
|
||||
if not email_regex.match(value):
|
||||
raise ValidationError('Invalid email')
|
||||
|
||||
|
||||
user_schema = UserSchema()
|
||||
user_schema_load_json = UserSchema(load_json=True)
|
||||
users_schema = UserSchema(many=True)
|
||||
@@ -142,3 +152,5 @@ email_notification_schema = EmailNotificationSchema()
|
||||
notification_status_schema = NotificationStatusSchema()
|
||||
notifications_status_schema = NotificationStatusSchema(many=True)
|
||||
notification_status_schema_load_json = NotificationStatusSchema(load_json=True)
|
||||
invited_user_schema = InvitedUserSchema()
|
||||
invited_users_schema = InvitedUserSchema(many=True)
|
||||
|
||||
26
migrations/versions/0023_drop_token.py
Normal file
26
migrations/versions/0023_drop_token.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 0023_drop_token
|
||||
Revises: 0022_add_invite_users
|
||||
Create Date: 2016-02-24 13:58:04.440296
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '0023_drop_token'
|
||||
down_revision = '0022_add_invite_users'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('invited_users', '_token')
|
||||
### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('invited_users', sa.Column('_token', sa.VARCHAR(), autoincrement=False, nullable=False))
|
||||
### end Alembic commands ###
|
||||
23
tests/app/dao/test_invited_user_dao.py
Normal file
23
tests/app/dao/test_invited_user_dao.py
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
from app.models import InvitedUser
|
||||
|
||||
from app.dao.invited_user_dao import save_invited_user
|
||||
|
||||
|
||||
def test_create_invited_user(notify_db, notify_db_session, sample_service):
|
||||
assert InvitedUser.query.count() == 0
|
||||
email_address = 'invited_user@service.gov.uk'
|
||||
invite_from = sample_service.users[0]
|
||||
|
||||
data = {
|
||||
'service': sample_service,
|
||||
'email_address': email_address,
|
||||
'from_user': invite_from
|
||||
}
|
||||
|
||||
invited_user = InvitedUser(**data)
|
||||
save_invited_user(invited_user)
|
||||
|
||||
assert InvitedUser.query.count() == 1
|
||||
assert invited_user.email_address == email_address
|
||||
assert invited_user.from_user == invite_from
|
||||
0
tests/app/invite/__init__.py
Normal file
0
tests/app/invite/__init__.py
Normal file
70
tests/app/invite/test_invite_rest.py
Normal file
70
tests/app/invite/test_invite_rest.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import json
|
||||
|
||||
from tests import create_authorization_header
|
||||
|
||||
|
||||
def test_create_invited_user(notify_api, sample_service):
|
||||
with notify_api.test_request_context():
|
||||
with notify_api.test_client() as client:
|
||||
|
||||
email_address = 'invited_user@service.gov.uk'
|
||||
invite_from = sample_service.users[0]
|
||||
|
||||
data = {
|
||||
'service': str(sample_service.id),
|
||||
'email_address': email_address,
|
||||
'from_user': invite_from.id
|
||||
}
|
||||
|
||||
data = json.dumps(data)
|
||||
|
||||
auth_header = create_authorization_header(
|
||||
path='/service/{}/invite'.format(sample_service.id),
|
||||
method='POST',
|
||||
request_body=data
|
||||
)
|
||||
|
||||
response = client.post(
|
||||
'/service/{}/invite'.format(sample_service.id),
|
||||
headers=[('Content-Type', 'application/json'), auth_header],
|
||||
data=data
|
||||
)
|
||||
assert response.status_code == 201
|
||||
json_resp = json.loads(response.get_data(as_text=True))
|
||||
|
||||
assert json_resp['data']['service'] == str(sample_service.id)
|
||||
assert json_resp['data']['email_address'] == email_address
|
||||
assert json_resp['data']['from_user'] == invite_from.id
|
||||
assert json_resp['data']['id']
|
||||
|
||||
|
||||
def test_create_invited_user_invalid_email(notify_api, sample_service):
|
||||
with notify_api.test_request_context():
|
||||
with notify_api.test_client() as client:
|
||||
|
||||
email_address = 'notanemail'
|
||||
invite_from = sample_service.users[0]
|
||||
|
||||
data = {
|
||||
'service': str(sample_service.id),
|
||||
'email_address': email_address,
|
||||
'from_user': invite_from.id
|
||||
}
|
||||
|
||||
data = json.dumps(data)
|
||||
|
||||
auth_header = create_authorization_header(
|
||||
path='/service/{}/invite'.format(sample_service.id),
|
||||
method='POST',
|
||||
request_body=data
|
||||
)
|
||||
|
||||
response = client.post(
|
||||
'/service/{}/invite'.format(sample_service.id),
|
||||
headers=[('Content-Type', 'application/json'), auth_header],
|
||||
data=data
|
||||
)
|
||||
assert response.status_code == 400
|
||||
json_resp = json.loads(response.get_data(as_text=True))
|
||||
assert json_resp['result'] == 'error'
|
||||
assert json_resp['message'] == {'email_address': ['Invalid email']}
|
||||
Reference in New Issue
Block a user