reports.py
353 lines
| 11.6 KiB
| text/x-python
|
PythonLexer
r0 | # -*- coding: utf-8 -*- | |||
r112 | # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors | |||
r0 | # | |||
r112 | # Licensed under the Apache License, Version 2.0 (the "License"); | |||
# you may not use this file except in compliance with the License. | ||||
# You may obtain a copy of the License at | ||||
r0 | # | |||
r112 | # http://www.apache.org/licenses/LICENSE-2.0 | |||
r0 | # | |||
r112 | # Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | ||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
# See the License for the specific language governing permissions and | ||||
# limitations under the License. | ||||
r0 | ||||
import logging | ||||
from datetime import datetime, timedelta | ||||
from pyramid.view import view_config | ||||
from pyramid.httpexceptions import HTTPUnprocessableEntity | ||||
r135 | from ziggurat_foundations.models.services.resource import ResourceService | |||
from ziggurat_foundations.models.services.user import UserService | ||||
r0 | from appenlight.models import DBSession | |||
from appenlight.models.user import User | ||||
from appenlight.models.report_comment import ReportComment | ||||
from appenlight.models.report_assignment import ReportAssignment | ||||
from appenlight.models.services.user import UserService | ||||
from appenlight.models.services.report_group import ReportGroupService | ||||
from appenlight import forms | ||||
from appenlight.lib.enums import ReportType | ||||
from appenlight.lib.helpers import gen_pagination_headers | ||||
from appenlight.lib.utils import build_filter_settings_from_query_dict | ||||
r153 | from appenlight.validators import ( | |||
ReportSearchSchema, | ||||
TagListSchema, | ||||
accepted_search_params, | ||||
) | ||||
r0 | from webob.multidict import MultiDict | |||
_ = str | ||||
log = logging.getLogger(__name__) | ||||
r153 | section_filters_key = "appenlight:reports:filter:%s" | |||
r0 | ||||
r153 | @view_config(route_name="reports", renderer="json", permission="authenticated") | |||
@view_config(route_name="slow_reports", renderer="json", permission="authenticated") | ||||
r0 | def index(request): | |||
""" | ||||
Returns list of report groups based on user search query | ||||
""" | ||||
if request.user: | ||||
request.user.last_login_date = datetime.utcnow() | ||||
r135 | applications = UserService.resources_with_perms( | |||
r153 | request.user, ["view"], resource_types=["application"] | |||
) | ||||
r0 | ||||
search_params = request.GET.mixed() | ||||
all_possible_app_ids = set([app.resource_id for app in applications]) | ||||
schema = ReportSearchSchema().bind(resources=all_possible_app_ids) | ||||
tag_schema = TagListSchema() | ||||
filter_settings = schema.deserialize(search_params) | ||||
r153 | tag_list = [ | |||
{"name": k, "value": v} | ||||
for k, v in filter_settings.items() | ||||
if k not in accepted_search_params | ||||
] | ||||
r0 | tags = tag_schema.deserialize(tag_list) | |||
r153 | filter_settings["tags"] = tags | |||
if request.matched_route.name == "slow_reports": | ||||
filter_settings["report_type"] = [ReportType.slow] | ||||
r0 | else: | |||
r153 | filter_settings["report_type"] = [ReportType.error] | |||
r0 | ||||
reports_paginator = ReportGroupService.get_paginator_by_app_ids( | ||||
r153 | app_ids=filter_settings["resource"], | |||
page=filter_settings["page"], | ||||
filter_settings=filter_settings, | ||||
r0 | ) | |||
reports = [] | ||||
r153 | include_keys = ( | |||
"id", | ||||
"http_status", | ||||
"report_type", | ||||
"resource_name", | ||||
"front_url", | ||||
"resource_id", | ||||
"error", | ||||
"url_path", | ||||
"tags", | ||||
"duration", | ||||
) | ||||
r0 | for report in reports_paginator.sa_items: | |||
reports.append(report.get_dict(request, include_keys=include_keys)) | ||||
headers = gen_pagination_headers(request, reports_paginator) | ||||
request.response.headers.update(headers) | ||||
return reports | ||||
r153 | @view_config( | |||
route_name="report_groups", renderer="json", permission="view", request_method="GET" | ||||
) | ||||
r0 | def view_report(request): | |||
""" | ||||
Show individual detailed report group along with latest report | ||||
""" | ||||
report_group = request.context.report_group | ||||
if not report_group.read: | ||||
report_group.read = True | ||||
r153 | report_id = request.params.get("reportId", request.params.get("report_id")) | |||
report_dict = report_group.get_report(report_id).get_dict(request, details=True) | ||||
r0 | # disallow browsing other occurences by anonymous | |||
if not request.user: | ||||
r153 | report_dict.pop("group_next_report", None) | |||
report_dict.pop("group_previous_report", None) | ||||
r0 | return report_dict | |||
r153 | @view_config( | |||
route_name="report_groups", | ||||
renderer="json", | ||||
permission="update_reports", | ||||
request_method="DELETE", | ||||
) | ||||
r0 | def remove(request): | |||
""" | ||||
Used to remove reourt groups from database | ||||
""" | ||||
report = request.context.report_group | ||||
form = forms.ReactorForm(request.POST, csrf_context=request) | ||||
form.validate() | ||||
DBSession.delete(report) | ||||
return True | ||||
r153 | @view_config( | |||
route_name="report_groups_property", | ||||
match_param="key=comments", | ||||
renderer="json", | ||||
permission="view", | ||||
request_method="POST", | ||||
) | ||||
r0 | def comment_create(request): | |||
""" | ||||
Creates user comments for report group, sends email notifications | ||||
of said comments | ||||
""" | ||||
report_group = request.context.report_group | ||||
application = request.context.resource | ||||
r153 | form = forms.CommentForm(MultiDict(request.unsafe_json_body), csrf_context=request) | |||
if request.method == "POST" and form.validate(): | ||||
comment = ReportComment( | ||||
owner_id=request.user.id, report_time=report_group.first_timestamp | ||||
) | ||||
r0 | form.populate_obj(comment) | |||
report_group.comments.append(comment) | ||||
r153 | perm_list = ResourceService.users_for_perm(application, "view") | |||
r0 | uids_to_notify = [] | |||
users_to_notify = [] | ||||
for perm in perm_list: | ||||
user = perm.user | ||||
r153 | if ( | |||
"@{}".format(user.user_name) in comment.body | ||||
and user.id not in uids_to_notify | ||||
): | ||||
r0 | uids_to_notify.append(user.id) | |||
users_to_notify.append(user) | ||||
commenters = ReportGroupService.users_commenting( | ||||
r153 | report_group, exclude_user_id=request.user.id | |||
) | ||||
r0 | for user in commenters: | |||
if user.id not in uids_to_notify: | ||||
uids_to_notify.append(user.id) | ||||
users_to_notify.append(user) | ||||
for user in users_to_notify: | ||||
r153 | email_vars = { | |||
"user": user, | ||||
"commenting_user": request.user, | ||||
"request": request, | ||||
"application": application, | ||||
"report_group": report_group, | ||||
"comment": comment, | ||||
"email_title": "AppEnlight :: New comment", | ||||
} | ||||
r0 | UserService.send_email( | |||
request, | ||||
recipients=[user.email], | ||||
variables=email_vars, | ||||
r153 | template="/email_templates/new_comment_report.jinja2", | |||
) | ||||
request.session.flash(_("Your comment was created")) | ||||
r0 | return comment.get_dict() | |||
else: | ||||
return form.errors | ||||
r153 | @view_config( | |||
route_name="report_groups_property", | ||||
match_param="key=assigned_users", | ||||
renderer="json", | ||||
permission="update_reports", | ||||
request_method="GET", | ||||
) | ||||
r0 | def assigned_users(request): | |||
""" | ||||
Returns list of users a specific report group is assigned for review | ||||
""" | ||||
report_group = request.context.report_group | ||||
application = request.context.resource | ||||
r153 | users = set([p.user for p in ResourceService.users_for_perm(application, "view")]) | |||
r0 | currently_assigned = [u.user_name for u in report_group.assigned_users] | |||
r153 | user_status = {"assigned": [], "unassigned": []} | |||
r0 | # handle users | |||
for user in users: | ||||
r153 | user_dict = { | |||
"user_name": user.user_name, | ||||
"gravatar_url": UserService.gravatar_url(user), | ||||
"name": "%s %s" % (user.first_name, user.last_name), | ||||
} | ||||
r0 | if user.user_name in currently_assigned: | |||
r153 | user_status["assigned"].append(user_dict) | |||
elif user_dict not in user_status["unassigned"]: | ||||
user_status["unassigned"].append(user_dict) | ||||
r0 | return user_status | |||
r153 | @view_config( | |||
route_name="report_groups_property", | ||||
match_param="key=assigned_users", | ||||
renderer="json", | ||||
permission="update_reports", | ||||
request_method="PATCH", | ||||
) | ||||
r0 | def assign_users(request): | |||
""" | ||||
Assigns specific report group to user for review - send email notification | ||||
""" | ||||
report_group = request.context.report_group | ||||
application = request.context.resource | ||||
currently_assigned = [u.user_name for u in report_group.assigned_users] | ||||
new_assigns = request.unsafe_json_body | ||||
# first unassign old users | ||||
r153 | for user_name in new_assigns["unassigned"]: | |||
r0 | if user_name in currently_assigned: | |||
r135 | user = UserService.by_user_name(user_name) | |||
r0 | report_group.assigned_users.remove(user) | |||
r153 | comment = ReportComment( | |||
owner_id=request.user.id, report_time=report_group.first_timestamp | ||||
) | ||||
comment.body = "Unassigned group from @%s" % user_name | ||||
r0 | report_group.comments.append(comment) | |||
# assign new users | ||||
r153 | for user_name in new_assigns["assigned"]: | |||
r0 | if user_name not in currently_assigned: | |||
r135 | user = UserService.by_user_name(user_name) | |||
r0 | if user in report_group.assigned_users: | |||
report_group.assigned_users.remove(user) | ||||
DBSession.flush() | ||||
assignment = ReportAssignment( | ||||
owner_id=user.id, | ||||
report_time=report_group.first_timestamp, | ||||
r153 | group_id=report_group.id, | |||
) | ||||
r0 | DBSession.add(assignment) | |||
r153 | comment = ReportComment( | |||
owner_id=request.user.id, report_time=report_group.first_timestamp | ||||
) | ||||
comment.body = "Assigned report_group to @%s" % user_name | ||||
r0 | report_group.comments.append(comment) | |||
r153 | email_vars = { | |||
"user": user, | ||||
"request": request, | ||||
"application": application, | ||||
"report_group": report_group, | ||||
"email_title": "AppEnlight :: Assigned Report", | ||||
} | ||||
UserService.send_email( | ||||
request, | ||||
recipients=[user.email], | ||||
variables=email_vars, | ||||
template="/email_templates/assigned_report.jinja2", | ||||
) | ||||
r0 | ||||
return True | ||||
r153 | @view_config( | |||
route_name="report_groups_property", | ||||
match_param="key=history", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def history(request): | |||
""" Separate error graph or similar graph""" | ||||
report_group = request.context.report_group | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (report_group.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
if not filter_settings.get("end_date"): | ||||
r0 | end_date = datetime.utcnow().replace(microsecond=0, second=0) | |||
r153 | filter_settings["end_date"] = end_date | |||
r0 | ||||
r153 | if not filter_settings.get("start_date"): | |||
r0 | delta = timedelta(days=30) | |||
r153 | filter_settings["start_date"] = filter_settings["end_date"] - delta | |||
r0 | ||||
r153 | filter_settings["group_id"] = report_group.id | |||
r0 | ||||
result = ReportGroupService.get_report_stats(request, filter_settings) | ||||
plot_data = [] | ||||
for row in result: | ||||
point = { | ||||
r153 | "x": row["x"], | |||
"reports": row["report"] + row["slow_report"] + row["not_found"], | ||||
} | ||||
r0 | plot_data.append(point) | |||
return plot_data | ||||
r153 | @view_config( | |||
route_name="report_groups", | ||||
renderer="json", | ||||
permission="update_reports", | ||||
request_method="PATCH", | ||||
) | ||||
r0 | def report_groups_PATCH(request): | |||
""" | ||||
Used to update the report group fixed status | ||||
""" | ||||
report_group = request.context.report_group | ||||
r153 | allowed_keys = ["public", "fixed"] | |||
r0 | for k, v in request.unsafe_json_body.items(): | |||
if k in allowed_keys: | ||||
setattr(report_group, k, v) | ||||
else: | ||||
return HTTPUnprocessableEntity() | ||||
return report_group.get_dict(request) | ||||