2016-04-14 15:09:59 +01:00
|
|
|
import uuid
|
2017-11-09 10:32:39 +00:00
|
|
|
from datetime import date, datetime, timedelta, time
|
2016-04-14 15:09:59 +01:00
|
|
|
|
2018-02-06 09:35:33 +00:00
|
|
|
from notifications_utils.statsd_decorators import statsd
|
2017-11-09 10:32:39 +00:00
|
|
|
from sqlalchemy import asc, func, extract
|
2017-09-25 09:44:16 +01:00
|
|
|
from sqlalchemy.orm import joinedload
|
2017-05-31 17:31:06 +01:00
|
|
|
from flask import current_app
|
2016-02-19 15:53:15 +00:00
|
|
|
|
2016-07-18 12:03:44 +01:00
|
|
|
from app import db
|
2016-04-14 15:09:59 +01:00
|
|
|
from app.dao.dao_utils import (
|
|
|
|
|
transactional,
|
2016-04-21 18:10:57 +01:00
|
|
|
version_class
|
2016-04-14 15:09:59 +01:00
|
|
|
)
|
2017-10-30 15:17:01 +00:00
|
|
|
from app.dao.date_util import get_financial_year
|
2017-09-11 17:40:37 +01:00
|
|
|
from app.dao.service_sms_sender_dao import insert_service_sms_sender
|
2017-11-14 14:32:34 +00:00
|
|
|
from app.dao.stats_template_usage_by_month_dao import dao_get_template_usage_stats_by_service
|
2016-05-06 11:07:11 +01:00
|
|
|
from app.models import (
|
2017-11-14 14:32:34 +00:00
|
|
|
AnnualBilling,
|
2016-05-06 11:07:11 +01:00
|
|
|
ApiKey,
|
2017-08-16 12:27:42 +01:00
|
|
|
InboundNumber,
|
2017-11-14 14:32:34 +00:00
|
|
|
InvitedUser,
|
2016-05-06 11:07:11 +01:00
|
|
|
Job,
|
|
|
|
|
Notification,
|
2017-11-14 14:32:34 +00:00
|
|
|
NotificationHistory,
|
2016-05-06 11:07:11 +01:00
|
|
|
Permission,
|
2017-11-14 14:32:34 +00:00
|
|
|
ProviderStatistics,
|
2016-09-16 13:47:09 +01:00
|
|
|
Service,
|
2017-05-17 14:09:18 +01:00
|
|
|
ServicePermission,
|
2017-11-14 14:32:34 +00:00
|
|
|
ServiceSmsSender,
|
|
|
|
|
Template,
|
|
|
|
|
TemplateHistory,
|
|
|
|
|
TemplateRedacted,
|
|
|
|
|
User,
|
|
|
|
|
VerifyCode,
|
|
|
|
|
EMAIL_TYPE,
|
|
|
|
|
INTERNATIONAL_SMS_TYPE,
|
2017-01-30 15:17:26 +00:00
|
|
|
KEY_TYPE_TEST,
|
|
|
|
|
NOTIFICATION_STATUS_TYPES,
|
2017-05-17 14:09:18 +01:00
|
|
|
SMS_TYPE,
|
2018-01-24 11:53:22 +00:00
|
|
|
TEMPLATE_TYPES,
|
|
|
|
|
LETTER_TYPE,
|
2017-10-19 11:06:28 +01:00
|
|
|
)
|
2017-03-29 11:47:41 +01:00
|
|
|
from app.utils import get_london_month_from_utc_column, get_london_midnight_in_utc
|
2016-05-06 11:07:11 +01:00
|
|
|
|
2017-10-19 11:06:28 +01:00
|
|
|
DEFAULT_SERVICE_PERMISSIONS = [
|
|
|
|
|
SMS_TYPE,
|
|
|
|
|
EMAIL_TYPE,
|
2018-01-24 11:53:22 +00:00
|
|
|
LETTER_TYPE,
|
2017-10-19 11:06:28 +01:00
|
|
|
INTERNATIONAL_SMS_TYPE,
|
|
|
|
|
]
|
|
|
|
|
|
2016-02-19 15:53:15 +00:00
|
|
|
|
2016-11-09 11:45:39 +00:00
|
|
|
def dao_fetch_all_services(only_active=False):
|
|
|
|
|
query = Service.query.order_by(
|
2016-07-15 11:34:59 +01:00
|
|
|
asc(Service.created_at)
|
|
|
|
|
).options(
|
|
|
|
|
joinedload('users')
|
2016-11-09 11:45:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if only_active:
|
|
|
|
|
query = query.filter(Service.active)
|
|
|
|
|
|
|
|
|
|
return query.all()
|
2016-02-19 15:53:15 +00:00
|
|
|
|
|
|
|
|
|
2016-11-09 15:07:23 +00:00
|
|
|
def dao_fetch_service_by_id(service_id, only_active=False):
|
|
|
|
|
query = Service.query.filter_by(
|
2016-07-15 11:34:59 +01:00
|
|
|
id=service_id
|
|
|
|
|
).options(
|
|
|
|
|
joinedload('users')
|
2016-11-09 15:07:23 +00:00
|
|
|
)
|
2016-02-19 15:53:15 +00:00
|
|
|
|
2016-11-09 15:07:23 +00:00
|
|
|
if only_active:
|
|
|
|
|
query = query.filter(Service.active)
|
2016-02-19 15:53:15 +00:00
|
|
|
|
2016-11-09 15:07:23 +00:00
|
|
|
return query.one()
|
|
|
|
|
|
|
|
|
|
|
2017-08-23 13:03:52 +01:00
|
|
|
def dao_fetch_service_by_inbound_number(number):
|
2017-08-16 12:27:42 +01:00
|
|
|
inbound_number = InboundNumber.query.filter(
|
2017-08-23 13:03:52 +01:00
|
|
|
InboundNumber.number == number,
|
2017-08-16 16:27:42 +01:00
|
|
|
InboundNumber.active
|
2017-08-16 12:27:42 +01:00
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
if not inbound_number:
|
2017-08-23 13:03:52 +01:00
|
|
|
return None
|
2017-08-16 12:27:42 +01:00
|
|
|
|
2017-05-22 11:26:47 +01:00
|
|
|
return Service.query.filter(
|
2017-08-23 13:03:52 +01:00
|
|
|
Service.id == inbound_number.service_id
|
|
|
|
|
).first()
|
2017-05-22 11:26:47 +01:00
|
|
|
|
|
|
|
|
|
2017-05-05 15:22:21 +01:00
|
|
|
def dao_fetch_service_by_id_with_api_keys(service_id, only_active=False):
|
|
|
|
|
query = Service.query.filter_by(
|
|
|
|
|
id=service_id
|
|
|
|
|
).options(
|
|
|
|
|
joinedload('api_keys')
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if only_active:
|
|
|
|
|
query = query.filter(Service.active)
|
|
|
|
|
|
|
|
|
|
return query.one()
|
|
|
|
|
|
|
|
|
|
|
2016-11-09 15:07:23 +00:00
|
|
|
def dao_fetch_all_services_by_user(user_id, only_active=False):
|
|
|
|
|
query = Service.query.filter(
|
2016-07-15 11:34:59 +01:00
|
|
|
Service.users.any(id=user_id)
|
|
|
|
|
).order_by(
|
|
|
|
|
asc(Service.created_at)
|
|
|
|
|
).options(
|
|
|
|
|
joinedload('users')
|
2016-11-09 15:07:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if only_active:
|
|
|
|
|
query = query.filter(Service.active)
|
|
|
|
|
|
|
|
|
|
return query.all()
|
2016-02-19 15:53:15 +00:00
|
|
|
|
|
|
|
|
|
2016-11-10 17:07:02 +00:00
|
|
|
@transactional
|
|
|
|
|
@version_class(Service)
|
|
|
|
|
@version_class(Template, TemplateHistory)
|
|
|
|
|
@version_class(ApiKey)
|
2017-01-30 16:32:44 +00:00
|
|
|
def dao_archive_service(service_id):
|
2016-11-10 17:07:02 +00:00
|
|
|
# have to eager load templates and api keys so that we don't flush when we loop through them
|
2016-11-11 12:43:51 +00:00
|
|
|
# to ensure that db.session still contains the models when it comes to creating history objects
|
2016-11-10 17:07:02 +00:00
|
|
|
service = Service.query.options(
|
|
|
|
|
joinedload('templates'),
|
2017-06-29 10:34:38 +01:00
|
|
|
joinedload('templates.template_redacted'),
|
2016-11-10 17:07:02 +00:00
|
|
|
joinedload('api_keys'),
|
|
|
|
|
).filter(Service.id == service_id).one()
|
|
|
|
|
|
|
|
|
|
service.active = False
|
|
|
|
|
service.name = '_archived_' + service.name
|
|
|
|
|
service.email_from = '_archived_' + service.email_from
|
|
|
|
|
|
|
|
|
|
for template in service.templates:
|
2016-11-14 14:10:40 +00:00
|
|
|
if not template.archived:
|
|
|
|
|
template.archived = True
|
2016-11-10 17:07:02 +00:00
|
|
|
|
|
|
|
|
for api_key in service.api_keys:
|
2016-11-14 14:10:40 +00:00
|
|
|
if not api_key.expiry_date:
|
|
|
|
|
api_key.expiry_date = datetime.utcnow()
|
2016-11-10 17:07:02 +00:00
|
|
|
|
|
|
|
|
|
2016-02-19 15:53:15 +00:00
|
|
|
def dao_fetch_service_by_id_and_user(service_id, user_id):
|
2016-07-15 11:34:59 +01:00
|
|
|
return Service.query.filter(
|
|
|
|
|
Service.users.any(id=user_id),
|
|
|
|
|
Service.id == service_id
|
|
|
|
|
).options(
|
|
|
|
|
joinedload('users')
|
|
|
|
|
).one()
|
2016-02-19 15:53:15 +00:00
|
|
|
|
|
|
|
|
|
2016-04-14 15:09:59 +01:00
|
|
|
@transactional
|
2016-04-21 18:10:57 +01:00
|
|
|
@version_class(Service)
|
2017-12-06 11:01:18 +00:00
|
|
|
def dao_create_service(service, user, service_id=None, service_permissions=None):
|
2017-05-31 17:31:06 +01:00
|
|
|
# the default property does not appear to work when there is a difference between the sqlalchemy schema and the
|
|
|
|
|
# db schema (ie: during a migration), so we have to set sms_sender manually here. After the GOVUK sms_sender
|
|
|
|
|
# migration is completed, this code should be able to be removed.
|
|
|
|
|
|
2017-10-19 11:06:28 +01:00
|
|
|
if service_permissions is None:
|
|
|
|
|
service_permissions = DEFAULT_SERVICE_PERMISSIONS
|
|
|
|
|
|
2016-04-14 15:09:59 +01:00
|
|
|
from app.dao.permissions_dao import permission_dao
|
|
|
|
|
service.users.append(user)
|
|
|
|
|
permission_dao.add_default_service_permissions_for_user(user, service)
|
2017-02-13 15:46:06 +00:00
|
|
|
service.id = service_id or uuid.uuid4() # must be set now so version history model can use same id
|
2016-11-08 13:49:47 +00:00
|
|
|
service.active = True
|
2016-05-31 12:49:06 +01:00
|
|
|
service.research_mode = False
|
2017-12-04 13:24:53 +00:00
|
|
|
service.crown = service.organisation_type == 'central'
|
2017-05-17 14:09:18 +01:00
|
|
|
|
2017-06-23 17:06:09 +01:00
|
|
|
for permission in service_permissions:
|
|
|
|
|
service_permission = ServicePermission(service_id=service.id, permission=permission)
|
|
|
|
|
service.permissions.append(service_permission)
|
2017-05-17 14:09:18 +01:00
|
|
|
|
2017-11-07 14:26:18 +00:00
|
|
|
# do we just add the default - or will we get a value from FE?
|
|
|
|
|
insert_service_sms_sender(service, current_app.config['FROM_NUMBER'])
|
2016-04-14 15:09:59 +01:00
|
|
|
db.session.add(service)
|
2016-01-07 17:31:17 +00:00
|
|
|
|
|
|
|
|
|
2016-04-14 15:09:59 +01:00
|
|
|
@transactional
|
2016-04-21 18:10:57 +01:00
|
|
|
@version_class(Service)
|
2016-02-19 15:53:15 +00:00
|
|
|
def dao_update_service(service):
|
|
|
|
|
db.session.add(service)
|
2016-01-12 10:39:49 +00:00
|
|
|
|
|
|
|
|
|
2017-05-04 17:09:04 +01:00
|
|
|
def dao_add_user_to_service(service, user, permissions=None):
|
|
|
|
|
permissions = permissions or []
|
2016-03-23 16:30:47 +00:00
|
|
|
try:
|
|
|
|
|
from app.dao.permissions_dao import permission_dao
|
|
|
|
|
service.users.append(user)
|
|
|
|
|
permission_dao.set_user_service_permission(user, service, permissions, _commit=False)
|
|
|
|
|
db.session.add(service)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
db.session.rollback()
|
|
|
|
|
raise e
|
|
|
|
|
else:
|
|
|
|
|
db.session.commit()
|
2016-02-19 15:53:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def dao_remove_user_from_service(service, user):
|
2016-03-22 13:14:23 +00:00
|
|
|
try:
|
|
|
|
|
from app.dao.permissions_dao import permission_dao
|
|
|
|
|
permission_dao.remove_user_service_permissions(user, service)
|
|
|
|
|
service.users.remove(user)
|
|
|
|
|
db.session.add(service)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
db.session.rollback()
|
|
|
|
|
raise e
|
|
|
|
|
else:
|
|
|
|
|
db.session.commit()
|
2016-05-06 11:07:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def delete_service_and_all_associated_db_objects(service):
|
|
|
|
|
|
|
|
|
|
def _delete_commit(query):
|
2017-06-28 17:19:53 +01:00
|
|
|
query.delete(synchronize_session=False)
|
2016-05-06 11:07:11 +01:00
|
|
|
db.session.commit()
|
|
|
|
|
|
2017-06-28 17:19:53 +01:00
|
|
|
subq = db.session.query(Template.id).filter_by(service=service).subquery()
|
|
|
|
|
_delete_commit(TemplateRedacted.query.filter(TemplateRedacted.template_id.in_(subq)))
|
|
|
|
|
|
2017-09-11 17:40:37 +01:00
|
|
|
_delete_commit(ServiceSmsSender.query.filter_by(service=service))
|
2016-05-06 11:07:11 +01:00
|
|
|
_delete_commit(ProviderStatistics.query.filter_by(service=service))
|
|
|
|
|
_delete_commit(InvitedUser.query.filter_by(service=service))
|
|
|
|
|
_delete_commit(Permission.query.filter_by(service=service))
|
2016-07-11 16:48:32 +01:00
|
|
|
_delete_commit(NotificationHistory.query.filter_by(service=service))
|
2016-05-06 11:07:11 +01:00
|
|
|
_delete_commit(Notification.query.filter_by(service=service))
|
2017-07-03 13:40:13 +01:00
|
|
|
_delete_commit(Job.query.filter_by(service=service))
|
2016-05-06 11:07:11 +01:00
|
|
|
_delete_commit(Template.query.filter_by(service=service))
|
2016-08-02 16:23:14 +01:00
|
|
|
_delete_commit(TemplateHistory.query.filter_by(service_id=service.id))
|
2017-05-17 14:09:18 +01:00
|
|
|
_delete_commit(ServicePermission.query.filter_by(service_id=service.id))
|
2017-08-02 15:35:56 +01:00
|
|
|
_delete_commit(ApiKey.query.filter_by(service=service))
|
|
|
|
|
_delete_commit(ApiKey.get_history_model().query.filter_by(service_id=service.id))
|
2017-10-25 11:35:13 +01:00
|
|
|
_delete_commit(AnnualBilling.query.filter_by(service_id=service.id))
|
2016-05-06 11:07:11 +01:00
|
|
|
|
|
|
|
|
verify_codes = VerifyCode.query.join(User).filter(User.id.in_([x.id for x in service.users]))
|
|
|
|
|
list(map(db.session.delete, verify_codes))
|
|
|
|
|
db.session.commit()
|
|
|
|
|
users = [x for x in service.users]
|
|
|
|
|
map(service.users.remove, users)
|
|
|
|
|
[service.users.remove(x) for x in users]
|
2016-05-11 15:52:49 +01:00
|
|
|
_delete_commit(Service.get_history_model().query.filter_by(id=service.id))
|
2016-05-06 11:07:11 +01:00
|
|
|
db.session.delete(service)
|
|
|
|
|
db.session.commit()
|
|
|
|
|
list(map(db.session.delete, users))
|
|
|
|
|
db.session.commit()
|
2016-07-18 12:03:44 +01:00
|
|
|
|
|
|
|
|
|
2016-08-05 10:44:43 +01:00
|
|
|
@statsd(namespace="dao")
|
2016-07-18 12:03:44 +01:00
|
|
|
def dao_fetch_stats_for_service(service_id):
|
2016-07-22 15:16:24 +01:00
|
|
|
return _stats_for_service_query(service_id).all()
|
|
|
|
|
|
|
|
|
|
|
2016-08-05 10:44:43 +01:00
|
|
|
@statsd(namespace="dao")
|
2016-07-22 15:16:24 +01:00
|
|
|
def dao_fetch_todays_stats_for_service(service_id):
|
|
|
|
|
return _stats_for_service_query(service_id).filter(
|
|
|
|
|
func.date(Notification.created_at) == date.today()
|
|
|
|
|
).all()
|
|
|
|
|
|
|
|
|
|
|
2016-10-03 10:57:10 +01:00
|
|
|
def fetch_todays_total_message_count(service_id):
|
|
|
|
|
result = db.session.query(
|
|
|
|
|
func.count(Notification.id).label('count')
|
|
|
|
|
).filter(
|
|
|
|
|
Notification.service_id == service_id,
|
|
|
|
|
Notification.key_type != KEY_TYPE_TEST,
|
|
|
|
|
func.date(Notification.created_at) == date.today()
|
|
|
|
|
).group_by(
|
|
|
|
|
Notification.notification_type,
|
|
|
|
|
Notification.status,
|
|
|
|
|
).first()
|
|
|
|
|
return 0 if result is None else result.count
|
|
|
|
|
|
|
|
|
|
|
2016-07-22 15:16:24 +01:00
|
|
|
def _stats_for_service_query(service_id):
|
2016-07-18 12:03:44 +01:00
|
|
|
return db.session.query(
|
|
|
|
|
Notification.notification_type,
|
2017-07-06 14:20:24 +01:00
|
|
|
Notification.status,
|
2016-07-18 12:03:44 +01:00
|
|
|
func.count(Notification.id).label('count')
|
|
|
|
|
).filter(
|
2016-09-16 13:47:09 +01:00
|
|
|
Notification.service_id == service_id,
|
|
|
|
|
Notification.key_type != KEY_TYPE_TEST
|
2016-07-18 12:03:44 +01:00
|
|
|
).group_by(
|
|
|
|
|
Notification.notification_type,
|
|
|
|
|
Notification.status,
|
2016-07-22 15:16:24 +01:00
|
|
|
)
|
2016-07-26 11:00:03 +01:00
|
|
|
|
|
|
|
|
|
2017-01-30 15:17:26 +00:00
|
|
|
@statsd(namespace="dao")
|
|
|
|
|
def dao_fetch_monthly_historical_stats_for_service(service_id, year):
|
2017-01-30 16:46:47 +00:00
|
|
|
month = get_london_month_from_utc_column(NotificationHistory.created_at)
|
2017-01-30 15:17:26 +00:00
|
|
|
|
2017-04-26 14:16:47 +01:00
|
|
|
start_date, end_date = get_financial_year(year)
|
2017-01-30 15:17:26 +00:00
|
|
|
rows = db.session.query(
|
|
|
|
|
NotificationHistory.notification_type,
|
2017-07-06 14:20:24 +01:00
|
|
|
NotificationHistory.status,
|
2017-01-30 15:17:26 +00:00
|
|
|
month,
|
|
|
|
|
func.count(NotificationHistory.id).label('count')
|
|
|
|
|
).filter(
|
|
|
|
|
NotificationHistory.service_id == service_id,
|
2017-05-02 10:00:47 +01:00
|
|
|
NotificationHistory.created_at.between(start_date, end_date)
|
2017-01-30 15:17:26 +00:00
|
|
|
).group_by(
|
|
|
|
|
NotificationHistory.notification_type,
|
|
|
|
|
NotificationHistory.status,
|
|
|
|
|
month
|
|
|
|
|
).order_by(
|
|
|
|
|
month
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
months = {
|
2017-11-28 13:49:14 +00:00
|
|
|
datetime.strftime(created_date, '%Y-%m'): {
|
Make sure status dictionary is assinged each time
The status dictionary was being assigned once, and then subsequent
uses of it were by reference. This meant that each template type was
pointing at the same dictionary, and updating one meant updating all.
This commit adds a dictionary comprehension, which gets evaluated once
for each template type, so each template type has its own `dict` of
statuses.
Before
--
```
Email SMS Letter
| | |
{'sending':, 'failed', …}
```
After
--
```
Email SMS Letter
| | |
{'sending':, {'sending':, {'sending':,
'failed', 'failed', 'failed',
…} …} …}
```
2017-02-07 13:06:32 +00:00
|
|
|
template_type: dict.fromkeys(
|
2017-01-30 15:17:26 +00:00
|
|
|
NOTIFICATION_STATUS_TYPES,
|
|
|
|
|
0
|
|
|
|
|
)
|
Make sure status dictionary is assinged each time
The status dictionary was being assigned once, and then subsequent
uses of it were by reference. This meant that each template type was
pointing at the same dictionary, and updating one meant updating all.
This commit adds a dictionary comprehension, which gets evaluated once
for each template type, so each template type has its own `dict` of
statuses.
Before
--
```
Email SMS Letter
| | |
{'sending':, 'failed', …}
```
After
--
```
Email SMS Letter
| | |
{'sending':, {'sending':, {'sending':,
'failed', 'failed', 'failed',
…} …} …}
```
2017-02-07 13:06:32 +00:00
|
|
|
for template_type in TEMPLATE_TYPES
|
|
|
|
|
}
|
2017-11-28 13:49:14 +00:00
|
|
|
for created_date in [
|
2017-01-30 15:17:26 +00:00
|
|
|
datetime(year, month, 1) for month in range(4, 13)
|
|
|
|
|
] + [
|
|
|
|
|
datetime(year + 1, month, 1) for month in range(1, 4)
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-28 13:49:14 +00:00
|
|
|
for notification_type, status, created_date, count in rows:
|
|
|
|
|
months[datetime.strftime(created_date, "%Y-%m")][notification_type][status] = count
|
2017-01-30 15:17:26 +00:00
|
|
|
|
|
|
|
|
return months
|
|
|
|
|
|
|
|
|
|
|
2016-08-11 17:24:44 +01:00
|
|
|
@statsd(namespace='dao')
|
2017-10-26 12:15:52 +01:00
|
|
|
def dao_fetch_todays_stats_for_all_services(include_from_test_key=True, only_active=True):
|
2018-03-20 15:48:32 +00:00
|
|
|
today = date.today()
|
|
|
|
|
start_date = get_london_midnight_in_utc(today)
|
|
|
|
|
end_date = get_london_midnight_in_utc(today + timedelta(days=1))
|
2017-09-15 14:40:56 +01:00
|
|
|
|
2017-10-25 10:40:02 +01:00
|
|
|
subquery = db.session.query(
|
2016-08-11 17:24:44 +01:00
|
|
|
Notification.notification_type,
|
2017-07-06 14:20:24 +01:00
|
|
|
Notification.status,
|
2016-08-19 16:36:20 +01:00
|
|
|
Notification.service_id,
|
2016-08-11 17:24:44 +01:00
|
|
|
func.count(Notification.id).label('count')
|
|
|
|
|
).filter(
|
2018-03-20 15:48:32 +00:00
|
|
|
Notification.created_at >= start_date,
|
|
|
|
|
Notification.created_at < end_date
|
2016-08-11 17:24:44 +01:00
|
|
|
).group_by(
|
|
|
|
|
Notification.notification_type,
|
|
|
|
|
Notification.status,
|
|
|
|
|
Notification.service_id
|
|
|
|
|
)
|
2016-12-02 16:43:24 +00:00
|
|
|
|
|
|
|
|
if not include_from_test_key:
|
2017-10-25 10:40:02 +01:00
|
|
|
subquery = subquery.filter(Notification.key_type != KEY_TYPE_TEST)
|
|
|
|
|
|
|
|
|
|
subquery = subquery.subquery()
|
|
|
|
|
|
|
|
|
|
query = db.session.query(
|
|
|
|
|
Service.id.label('service_id'),
|
|
|
|
|
Service.name,
|
|
|
|
|
Service.restricted,
|
|
|
|
|
Service.research_mode,
|
2017-10-26 12:15:52 +01:00
|
|
|
Service.active,
|
|
|
|
|
Service.created_at,
|
2017-10-25 10:40:02 +01:00
|
|
|
subquery.c.notification_type,
|
|
|
|
|
subquery.c.status,
|
|
|
|
|
subquery.c.count
|
2017-10-26 12:15:52 +01:00
|
|
|
).outerjoin(
|
2017-10-25 10:40:02 +01:00
|
|
|
subquery,
|
|
|
|
|
subquery.c.service_id == Service.id
|
|
|
|
|
).order_by(Service.id)
|
2016-12-02 16:43:24 +00:00
|
|
|
|
2017-10-26 12:15:52 +01:00
|
|
|
if only_active:
|
|
|
|
|
query = query.filter(Service.active)
|
|
|
|
|
|
2016-12-29 13:28:55 +00:00
|
|
|
return query.all()
|
2016-12-28 15:39:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@statsd(namespace='dao')
|
2017-10-26 12:15:52 +01:00
|
|
|
def fetch_stats_by_date_range_for_all_services(start_date, end_date, include_from_test_key=True, only_active=True):
|
2017-03-29 11:47:41 +01:00
|
|
|
start_date = get_london_midnight_in_utc(start_date)
|
2017-04-03 15:52:52 +01:00
|
|
|
end_date = get_london_midnight_in_utc(end_date + timedelta(days=1))
|
2017-04-06 11:18:21 +01:00
|
|
|
table = NotificationHistory
|
2017-03-28 13:30:04 +01:00
|
|
|
|
2017-04-04 16:34:20 +01:00
|
|
|
if start_date >= datetime.utcnow() - timedelta(days=7):
|
2017-04-06 11:18:21 +01:00
|
|
|
table = Notification
|
2017-10-25 16:47:39 +01:00
|
|
|
subquery = db.session.query(
|
2017-04-06 11:18:21 +01:00
|
|
|
table.notification_type,
|
2017-07-06 14:20:24 +01:00
|
|
|
table.status,
|
2017-04-06 11:18:21 +01:00
|
|
|
table.service_id,
|
|
|
|
|
func.count(table.id).label('count')
|
|
|
|
|
).filter(
|
|
|
|
|
table.created_at >= start_date,
|
|
|
|
|
table.created_at < end_date
|
|
|
|
|
).group_by(
|
|
|
|
|
table.notification_type,
|
|
|
|
|
table.status,
|
|
|
|
|
table.service_id
|
|
|
|
|
)
|
|
|
|
|
if not include_from_test_key:
|
2017-10-25 16:47:39 +01:00
|
|
|
subquery = subquery.filter(table.key_type != KEY_TYPE_TEST)
|
|
|
|
|
subquery = subquery.subquery()
|
|
|
|
|
|
|
|
|
|
query = db.session.query(
|
|
|
|
|
Service.id.label('service_id'),
|
|
|
|
|
Service.name,
|
|
|
|
|
Service.restricted,
|
|
|
|
|
Service.research_mode,
|
2017-10-26 12:15:52 +01:00
|
|
|
Service.active,
|
|
|
|
|
Service.created_at,
|
2017-10-25 16:47:39 +01:00
|
|
|
subquery.c.notification_type,
|
|
|
|
|
subquery.c.status,
|
|
|
|
|
subquery.c.count
|
2017-10-26 12:15:52 +01:00
|
|
|
).outerjoin(
|
2017-10-25 16:47:39 +01:00
|
|
|
subquery,
|
|
|
|
|
subquery.c.service_id == Service.id
|
|
|
|
|
).order_by(Service.id)
|
2017-10-26 12:15:52 +01:00
|
|
|
if only_active:
|
|
|
|
|
query = query.filter(Service.active)
|
2016-12-28 15:39:55 +00:00
|
|
|
|
2016-12-29 13:28:55 +00:00
|
|
|
return query.all()
|
2017-01-30 16:32:44 +00:00
|
|
|
|
|
|
|
|
|
2017-10-23 10:58:06 +01:00
|
|
|
@statsd(namespace='dao')
|
|
|
|
|
def fetch_aggregate_stats_by_date_range_for_all_services(start_date, end_date, include_from_test_key=True):
|
|
|
|
|
start_date = get_london_midnight_in_utc(start_date)
|
|
|
|
|
end_date = get_london_midnight_in_utc(end_date + timedelta(days=1))
|
|
|
|
|
table = NotificationHistory
|
|
|
|
|
|
|
|
|
|
if start_date >= datetime.utcnow() - timedelta(days=7):
|
|
|
|
|
table = Notification
|
|
|
|
|
|
|
|
|
|
query = db.session.query(
|
|
|
|
|
table.notification_type,
|
|
|
|
|
table.status,
|
|
|
|
|
func.count(table.id).label('count')
|
|
|
|
|
).filter(
|
|
|
|
|
table.created_at >= start_date,
|
|
|
|
|
table.created_at < end_date
|
|
|
|
|
).group_by(
|
|
|
|
|
table.notification_type,
|
|
|
|
|
table.status
|
|
|
|
|
).order_by(
|
|
|
|
|
table.notification_type
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if not include_from_test_key:
|
|
|
|
|
query = query.filter(table.key_type != KEY_TYPE_TEST)
|
|
|
|
|
|
|
|
|
|
return query.all()
|
|
|
|
|
|
|
|
|
|
|
2017-01-30 16:32:44 +00:00
|
|
|
@transactional
|
|
|
|
|
@version_class(Service)
|
|
|
|
|
@version_class(ApiKey)
|
|
|
|
|
def dao_suspend_service(service_id):
|
|
|
|
|
# have to eager load api keys so that we don't flush when we loop through them
|
|
|
|
|
# to ensure that db.session still contains the models when it comes to creating history objects
|
|
|
|
|
service = Service.query.options(
|
|
|
|
|
joinedload('api_keys'),
|
|
|
|
|
).filter(Service.id == service_id).one()
|
|
|
|
|
|
|
|
|
|
service.active = False
|
|
|
|
|
|
|
|
|
|
for api_key in service.api_keys:
|
|
|
|
|
if not api_key.expiry_date:
|
|
|
|
|
api_key.expiry_date = datetime.utcnow()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@transactional
|
|
|
|
|
@version_class(Service)
|
|
|
|
|
def dao_resume_service(service_id):
|
|
|
|
|
service = Service.query.get(service_id)
|
|
|
|
|
service.active = True
|
2017-05-10 15:58:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def dao_fetch_active_users_for_service(service_id):
|
|
|
|
|
query = User.query.filter(
|
|
|
|
|
User.user_to_service.any(id=service_id),
|
|
|
|
|
User.state == 'active'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return query.all()
|
2017-11-09 10:32:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@statsd(namespace="dao")
|
|
|
|
|
def dao_fetch_monthly_historical_stats_by_template():
|
|
|
|
|
month = get_london_month_from_utc_column(NotificationHistory.created_at)
|
2017-11-09 14:13:42 +00:00
|
|
|
year = func.date_trunc("year", NotificationHistory.created_at)
|
2017-11-09 10:32:39 +00:00
|
|
|
end_date = datetime.combine(date.today(), time.min)
|
|
|
|
|
|
|
|
|
|
return db.session.query(
|
|
|
|
|
NotificationHistory.template_id,
|
2017-11-09 14:13:42 +00:00
|
|
|
extract('month', month).label('month'),
|
|
|
|
|
extract('year', year).label('year'),
|
2017-11-09 10:32:39 +00:00
|
|
|
func.count().label('count')
|
|
|
|
|
).filter(
|
|
|
|
|
NotificationHistory.created_at < end_date
|
|
|
|
|
).group_by(
|
|
|
|
|
NotificationHistory.template_id,
|
|
|
|
|
month,
|
|
|
|
|
year
|
|
|
|
|
).order_by(
|
2017-11-14 14:32:34 +00:00
|
|
|
year,
|
|
|
|
|
month
|
2017-11-09 10:32:39 +00:00
|
|
|
).all()
|
2017-11-14 14:32:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@statsd(namespace="dao")
|
2017-11-15 15:55:00 +00:00
|
|
|
def dao_fetch_monthly_historical_usage_by_template_for_service(service_id, year):
|
2017-11-14 14:32:34 +00:00
|
|
|
|
2017-11-15 15:55:00 +00:00
|
|
|
results = dao_get_template_usage_stats_by_service(service_id, year)
|
2017-11-14 14:32:34 +00:00
|
|
|
|
2017-11-20 10:01:45 +00:00
|
|
|
stats = []
|
2017-11-14 14:32:34 +00:00
|
|
|
for result in results:
|
2017-11-15 15:55:00 +00:00
|
|
|
stat = type("", (), {})()
|
|
|
|
|
stat.template_id = result.template_id
|
2017-11-16 14:41:07 +00:00
|
|
|
stat.template_type = result.template_type
|
2017-11-15 15:55:00 +00:00
|
|
|
stat.name = str(result.name)
|
|
|
|
|
stat.month = result.month
|
|
|
|
|
stat.year = result.year
|
|
|
|
|
stat.count = result.count
|
2018-03-07 15:42:59 +00:00
|
|
|
stat.is_precompiled_letter = result.is_precompiled_letter
|
2017-11-14 14:32:34 +00:00
|
|
|
stats.append(stat)
|
|
|
|
|
|
|
|
|
|
month = get_london_month_from_utc_column(Notification.created_at)
|
2017-11-21 16:29:20 +00:00
|
|
|
year_func = func.date_trunc("year", Notification.created_at)
|
2017-11-14 14:32:34 +00:00
|
|
|
start_date = datetime.combine(date.today(), time.min)
|
|
|
|
|
|
2017-11-21 16:29:20 +00:00
|
|
|
fy_start, fy_end = get_financial_year(year)
|
|
|
|
|
|
|
|
|
|
if fy_start < datetime.now() < fy_end:
|
|
|
|
|
today_results = db.session.query(
|
|
|
|
|
Notification.template_id,
|
2018-03-07 15:42:59 +00:00
|
|
|
Template.is_precompiled_letter,
|
2017-11-21 16:29:20 +00:00
|
|
|
Template.name,
|
|
|
|
|
Template.template_type,
|
|
|
|
|
extract('month', month).label('month'),
|
|
|
|
|
extract('year', year_func).label('year'),
|
|
|
|
|
func.count().label('count')
|
|
|
|
|
).join(
|
|
|
|
|
Template, Notification.template_id == Template.id,
|
|
|
|
|
).filter(
|
|
|
|
|
Notification.created_at >= start_date,
|
2018-02-06 14:31:12 +00:00
|
|
|
Notification.service_id == service_id,
|
|
|
|
|
# we don't want to include test keys
|
|
|
|
|
Notification.key_type != KEY_TYPE_TEST
|
2017-11-21 16:29:20 +00:00
|
|
|
).group_by(
|
|
|
|
|
Notification.template_id,
|
2018-03-05 13:38:41 +00:00
|
|
|
Template.hidden,
|
2017-11-21 16:29:20 +00:00
|
|
|
Template.name,
|
|
|
|
|
Template.template_type,
|
|
|
|
|
month,
|
|
|
|
|
year_func
|
|
|
|
|
).order_by(
|
|
|
|
|
Notification.template_id
|
|
|
|
|
).all()
|
|
|
|
|
|
|
|
|
|
for today_result in today_results:
|
|
|
|
|
add_to_stats = True
|
|
|
|
|
for stat in stats:
|
|
|
|
|
if today_result.template_id == stat.template_id and today_result.month == stat.month \
|
|
|
|
|
and today_result.year == stat.year:
|
|
|
|
|
stat.count = stat.count + today_result.count
|
|
|
|
|
add_to_stats = False
|
|
|
|
|
|
|
|
|
|
if add_to_stats:
|
2018-02-06 14:31:12 +00:00
|
|
|
new_stat = type("StatsTemplateUsageByMonth", (), {})()
|
2017-11-21 16:29:20 +00:00
|
|
|
new_stat.template_id = today_result.template_id
|
|
|
|
|
new_stat.template_type = today_result.template_type
|
|
|
|
|
new_stat.name = today_result.name
|
|
|
|
|
new_stat.month = int(today_result.month)
|
|
|
|
|
new_stat.year = int(today_result.year)
|
|
|
|
|
new_stat.count = today_result.count
|
2018-03-07 15:42:59 +00:00
|
|
|
new_stat.is_precompiled_letter = today_result.is_precompiled_letter
|
2017-11-21 16:29:20 +00:00
|
|
|
stats.append(new_stat)
|
2017-11-14 14:32:34 +00:00
|
|
|
|
|
|
|
|
return stats
|