mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-04 05:30:53 -04:00
Working tests and provider stats table.
Fix for tests and import error. Added tests and updated for code review comments.
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
import uuid
|
||||
from app import db
|
||||
from app.models import (Template, Service)
|
||||
from sqlalchemy import asc
|
||||
|
||||
from app.dao.dao_utils import (
|
||||
transactional,
|
||||
version_class
|
||||
)
|
||||
|
||||
|
||||
@transactional
|
||||
@version_class(Template)
|
||||
def dao_create_template(template):
|
||||
template.id = uuid.uuid4() # must be set now so version history model can use same id
|
||||
db.session.add(template)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@transactional
|
||||
@version_class(Template)
|
||||
def dao_update_template(template):
|
||||
db.session.add(template)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def dao_get_template_by_id_and_service_id(template_id, service_id):
|
||||
|
||||
@@ -59,4 +59,11 @@ def register_errors(blueprint):
|
||||
@blueprint.app_errorhandler(SQLAlchemyError)
|
||||
def db_error(e):
|
||||
current_app.logger.exception(e)
|
||||
return jsonify(result='error', message=str(e)), 500
|
||||
if e.orig.pgerror and \
|
||||
('duplicate key value violates unique constraint "services_name_key"' in e.orig.pgerror or
|
||||
'duplicate key value violates unique constraint "services_email_from_key"' in e.orig.pgerror):
|
||||
return jsonify(
|
||||
result='error',
|
||||
message={'name': ["Duplicate service name '{}'".format(e.params.get('name', ''))]}
|
||||
), 400
|
||||
return jsonify(result='error', message="Internal server error"), 500
|
||||
|
||||
@@ -180,7 +180,6 @@ def create_history(obj):
|
||||
|
||||
obj_state = attributes.instance_state(obj)
|
||||
data = {}
|
||||
|
||||
for prop in obj_mapper.iterate_properties:
|
||||
|
||||
# expired object attributes and also deferred cols might not
|
||||
|
||||
@@ -152,7 +152,7 @@ TEMPLATE_TYPE_LETTER = 'letter'
|
||||
TEMPLATE_TYPES = [TEMPLATE_TYPE_SMS, TEMPLATE_TYPE_EMAIL, TEMPLATE_TYPE_LETTER]
|
||||
|
||||
|
||||
class Template(db.Model):
|
||||
class Template(db.Model, Versioned):
|
||||
__tablename__ = 'templates'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
@@ -174,6 +174,8 @@ class Template(db.Model):
|
||||
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False, nullable=False)
|
||||
service = db.relationship('Service', backref=db.backref('templates', lazy='dynamic'))
|
||||
subject = db.Column(db.Text, index=False, unique=True, nullable=True)
|
||||
created_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), index=True, nullable=False)
|
||||
created_by = db.relationship('User')
|
||||
|
||||
|
||||
MMG_PROVIDER = "mmg"
|
||||
|
||||
@@ -7,8 +7,9 @@ from marshmallow import (
|
||||
validates_schema,
|
||||
pre_load
|
||||
)
|
||||
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from marshmallow_sqlalchemy import field_for
|
||||
from marshmallow_sqlalchemy.convert import ModelConverter
|
||||
|
||||
from notifications_utils.recipients import (
|
||||
validate_email_address,
|
||||
@@ -35,17 +36,6 @@ class BaseSchema(ma.ModelSchema):
|
||||
self.load_json = load_json
|
||||
super(BaseSchema, self).__init__(*args, **kwargs)
|
||||
|
||||
__envelope__ = {
|
||||
'single': None,
|
||||
'many': None
|
||||
}
|
||||
|
||||
def get_envelope_key(self, many):
|
||||
"""Helper to get the envelope key."""
|
||||
key = self.__envelope__['many'] if many else self.__envelope__['single']
|
||||
assert key is not None, "Envelope key undefined"
|
||||
return key
|
||||
|
||||
@post_load
|
||||
def make_instance(self, data):
|
||||
"""Deserialize data to an instance of the model. Update an existing row
|
||||
@@ -58,6 +48,25 @@ class BaseSchema(ma.ModelSchema):
|
||||
return super(BaseSchema, self).make_instance(data)
|
||||
|
||||
|
||||
class CreatedBySchema(ma.Schema):
|
||||
|
||||
created_by = fields.Str(required=True, load_only=True)
|
||||
|
||||
@validates_schema
|
||||
def validates_created_by(self, data):
|
||||
try:
|
||||
if not isinstance(data.get('created_by'), models.User):
|
||||
created_by = models.User.query.filter_by(id=data.get('created_by')).one()
|
||||
except:
|
||||
raise ValidationError('Invalid template created_by: {}'.format(data))
|
||||
|
||||
@post_load
|
||||
def format_created_by(self, item):
|
||||
if not isinstance(item.get('created_by'), models.User):
|
||||
item['created_by'] = models.User.query.filter_by(id=item.get('created_by')).one()
|
||||
return item
|
||||
|
||||
|
||||
class UserSchema(BaseSchema):
|
||||
|
||||
permissions = fields.Method("user_permissions", dump_only=True)
|
||||
@@ -80,7 +89,7 @@ class UserSchema(BaseSchema):
|
||||
"_password", "verify_codes")
|
||||
|
||||
|
||||
class ServiceSchema(BaseSchema):
|
||||
class ServiceSchema(BaseSchema, CreatedBySchema):
|
||||
class Meta:
|
||||
model = models.Service
|
||||
exclude = ("updated_at", "created_at", "api_keys", "templates", "jobs", 'old_id')
|
||||
@@ -92,12 +101,13 @@ class NotificationModelSchema(BaseSchema):
|
||||
|
||||
|
||||
class BaseTemplateSchema(BaseSchema):
|
||||
|
||||
class Meta:
|
||||
model = models.Template
|
||||
exclude = ("updated_at", "created_at", "service_id", "jobs")
|
||||
|
||||
|
||||
class TemplateSchema(BaseTemplateSchema):
|
||||
class TemplateSchema(BaseTemplateSchema, CreatedBySchema):
|
||||
|
||||
@validates_schema
|
||||
def validate_type(self, data):
|
||||
@@ -113,7 +123,7 @@ class NotificationsStatisticsSchema(BaseSchema):
|
||||
model = models.NotificationStatistics
|
||||
|
||||
|
||||
class ApiKeySchema(BaseSchema):
|
||||
class ApiKeySchema(BaseSchema, CreatedBySchema):
|
||||
class Meta:
|
||||
model = models.ApiKey
|
||||
exclude = ("service", "secret")
|
||||
@@ -303,6 +313,18 @@ class ApiKeyHistorySchema(ma.Schema):
|
||||
created_by_id = fields.UUID()
|
||||
|
||||
|
||||
class TemplateHistorySchema(ma.Schema):
|
||||
id = fields.UUID()
|
||||
name = fields.String()
|
||||
template_type = fields.String()
|
||||
created_at = fields.DateTime()
|
||||
updated_at = fields.DateTime()
|
||||
content = fields.String()
|
||||
service_id = fields.UUID()
|
||||
subject = fields.String()
|
||||
created_by_id = fields.UUID()
|
||||
|
||||
|
||||
user_schema = UserSchema()
|
||||
user_schema_load_json = UserSchema(load_json=True)
|
||||
service_schema = ServiceSchema()
|
||||
@@ -329,3 +351,4 @@ notifications_filter_schema = NotificationsFilterSchema()
|
||||
template_statistics_schema = TemplateStatisticsSchema()
|
||||
service_history_schema = ServiceHistorySchema()
|
||||
api_key_history_schema = ApiKeyHistorySchema()
|
||||
template_history_schema = TemplateHistorySchema()
|
||||
|
||||
@@ -185,9 +185,13 @@ def _process_permissions(user, service, permission_groups):
|
||||
# goes into how we want to fetch and view various items in history
|
||||
# tables. This is so product owner can pass stories as done
|
||||
@service.route('/<uuid:service_id>/history', methods=['GET'])
|
||||
def get_service_and_api_key_history(service_id):
|
||||
from app.models import Service, ApiKey
|
||||
from app.schemas import service_history_schema, api_key_history_schema
|
||||
def get_service_history(service_id):
|
||||
from app.models import (Service, ApiKey, Template)
|
||||
from app.schemas import (
|
||||
service_history_schema,
|
||||
api_key_history_schema,
|
||||
template_history_schema
|
||||
)
|
||||
|
||||
service_history = Service.get_history_model().query.filter_by(id=service_id).all()
|
||||
service_data, errors = service_history_schema.dump(service_history, many=True)
|
||||
@@ -200,6 +204,12 @@ def get_service_and_api_key_history(service_id):
|
||||
if errors:
|
||||
return jsonify(result="error", message=errors), 400
|
||||
|
||||
data = {'service_history': service_data, 'api_key_history': api_keys_data}
|
||||
template_history = Template.get_history_model().query.filter_by(service_id=service_id).all()
|
||||
template_data, errors = template_history_schema.dump(template_history, many=True)
|
||||
|
||||
data = {
|
||||
'service_history': service_data,
|
||||
'api_key_history': api_keys_data,
|
||||
'template_history': template_data}
|
||||
|
||||
return jsonify(data=data)
|
||||
|
||||
@@ -28,7 +28,6 @@ register_errors(template)
|
||||
@template.route('', methods=['POST'])
|
||||
def create_template(service_id):
|
||||
fetched_service = dao_fetch_service_by_id(service_id=service_id)
|
||||
|
||||
new_template, errors = template_schema.load(request.get_json())
|
||||
if errors:
|
||||
return jsonify(result="error", message=errors), 400
|
||||
|
||||
Reference in New Issue
Block a user