applications.py
846 lines
| 27.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 copy | ||||
import json | ||||
import logging | ||||
from datetime import datetime, timedelta | ||||
import colander | ||||
from pyramid.httpexceptions import HTTPFound, HTTPUnprocessableEntity | ||||
from pyramid.view import view_config | ||||
from webob.multidict import MultiDict | ||||
from zope.sqlalchemy import mark_changed | ||||
from ziggurat_foundations.permissions import ANY_PERMISSION | ||||
import appenlight.forms as forms | ||||
from appenlight.models import DBSession | ||||
from appenlight.models.resource import Resource | ||||
from appenlight.models.application import Application | ||||
r153 | from appenlight.models.application_postprocess_conf import ApplicationPostprocessConf | |||
r135 | from ziggurat_foundations.models.services.user import UserService | |||
from ziggurat_foundations.models.services.resource import ResourceService | ||||
r153 | from ziggurat_foundations.models.services.user_resource_permission import ( | |||
UserResourcePermissionService, | ||||
) | ||||
r0 | from appenlight.models.user_resource_permission import UserResourcePermission | |||
from appenlight.models.group_resource_permission import GroupResourcePermission | ||||
from appenlight.models.services.application import ApplicationService | ||||
r153 | from appenlight.models.services.application_postprocess_conf import ( | |||
ApplicationPostprocessConfService, | ||||
) | ||||
r0 | from appenlight.models.services.group import GroupService | |||
r153 | from appenlight.models.services.group_resource_permission import ( | |||
GroupResourcePermissionService, | ||||
) | ||||
r0 | from appenlight.models.services.request_metric import RequestMetricService | |||
from appenlight.models.services.report_group import ReportGroupService | ||||
from appenlight.models.services.slow_call import SlowCallService | ||||
from appenlight.lib import helpers as h | ||||
from appenlight.lib.utils import build_filter_settings_from_query_dict | ||||
from appenlight.security import RootFactory | ||||
from appenlight.models.report import REPORT_TYPE_MATRIX | ||||
from appenlight.validators import build_rule_schema | ||||
_ = str | ||||
log = logging.getLogger(__name__) | ||||
def app_not_found(request, id): | ||||
""" | ||||
Redirects on non found and sets a flash message | ||||
""" | ||||
r153 | request.session.flash(_("Application not found"), "warning") | |||
return HTTPFound(location=request.route_url("applications", action="index")) | ||||
r0 | ||||
r153 | @view_config( | |||
route_name="applications_no_id", | ||||
renderer="json", | ||||
request_method="GET", | ||||
permission="authenticated", | ||||
) | ||||
r0 | def applications_list(request): | |||
""" | ||||
Applications list | ||||
if query params contain ?type=foo, it will list applications | ||||
with one of those permissions for user, | ||||
otherwise only list of owned applications will | ||||
be returned | ||||
appending ?root_list while being administration will allow to list all | ||||
applications in the system | ||||
""" | ||||
r153 | is_root = request.has_permission("root_administration", RootFactory(request)) | |||
if is_root and request.GET.get("root_list"): | ||||
r0 | resources = Resource.all().order_by(Resource.resource_name) | |||
r153 | resource_type = request.GET.get("resource_type", "application") | |||
r0 | if resource_type: | |||
r153 | resources = resources.filter(Resource.resource_type == resource_type) | |||
r0 | else: | |||
r153 | permissions = request.params.getall("permission") | |||
r0 | if permissions: | |||
r135 | resources = UserService.resources_with_perms( | |||
request.user, | ||||
r0 | permissions, | |||
r153 | resource_types=[request.GET.get("resource_type", "application")], | |||
) | ||||
r0 | else: | |||
resources = request.user.resources.filter( | ||||
r153 | Application.resource_type | |||
== request.GET.get("resource_type", "application") | ||||
) | ||||
return [ | ||||
r.get_dict( | ||||
include_keys=[ | ||||
"resource_id", | ||||
"resource_name", | ||||
"domains", | ||||
"owner_user_name", | ||||
"owner_group_name", | ||||
] | ||||
) | ||||
for r in resources | ||||
] | ||||
@view_config( | ||||
route_name="applications", renderer="json", request_method="GET", permission="view" | ||||
) | ||||
r0 | def application_GET(request): | |||
resource = request.context.resource | ||||
include_sensitive_info = False | ||||
r153 | if request.has_permission("edit"): | |||
r0 | include_sensitive_info = True | |||
resource_dict = resource.get_dict( | ||||
include_perms=include_sensitive_info, | ||||
r153 | include_processing_rules=include_sensitive_info, | |||
) | ||||
r0 | return resource_dict | |||
r153 | @view_config( | |||
route_name="applications_no_id", | ||||
request_method="POST", | ||||
renderer="json", | ||||
permission="create_resources", | ||||
) | ||||
r0 | def application_create(request): | |||
""" | ||||
Creates new application instances | ||||
""" | ||||
user = request.user | ||||
r153 | form = forms.ApplicationCreateForm( | |||
MultiDict(request.unsafe_json_body), csrf_context=request | ||||
) | ||||
r0 | if form.validate(): | |||
session = DBSession() | ||||
resource = Application() | ||||
DBSession.add(resource) | ||||
form.populate_obj(resource) | ||||
resource.api_key = resource.generate_api_key() | ||||
user.resources.append(resource) | ||||
r153 | request.session.flash(_("Application created")) | |||
r0 | DBSession.flush() | |||
mark_changed(session) | ||||
else: | ||||
return HTTPUnprocessableEntity(body=form.errors_json) | ||||
return resource.get_dict() | ||||
r153 | @view_config( | |||
route_name="applications", | ||||
request_method="PATCH", | ||||
renderer="json", | ||||
permission="edit", | ||||
) | ||||
r0 | def application_update(request): | |||
""" | ||||
Updates main application configuration | ||||
""" | ||||
resource = request.context.resource | ||||
if not resource: | ||||
return app_not_found() | ||||
# disallow setting permanent storage by non-admins | ||||
# use default/non-resource based context for this check | ||||
req_dict = copy.copy(request.unsafe_json_body) | ||||
r153 | if not request.has_permission("root_administration", RootFactory(request)): | |||
req_dict["allow_permanent_storage"] = "" | ||||
if not req_dict.get("uptime_url"): | ||||
r0 | # needed cause validator is still triggered by default | |||
r153 | req_dict.pop("uptime_url", "") | |||
application_form = forms.ApplicationUpdateForm( | ||||
MultiDict(req_dict), csrf_context=request | ||||
) | ||||
r0 | if application_form.validate(): | |||
application_form.populate_obj(resource) | ||||
r153 | request.session.flash(_("Application updated")) | |||
r0 | else: | |||
return HTTPUnprocessableEntity(body=application_form.errors_json) | ||||
include_sensitive_info = False | ||||
r153 | if request.has_permission("edit"): | |||
r0 | include_sensitive_info = True | |||
resource_dict = resource.get_dict( | ||||
include_perms=include_sensitive_info, | ||||
r153 | include_processing_rules=include_sensitive_info, | |||
) | ||||
r0 | return resource_dict | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=api_key", | ||||
request_method="POST", | ||||
renderer="json", | ||||
permission="delete", | ||||
) | ||||
r0 | def application_regenerate_key(request): | |||
""" | ||||
Regenerates API keys for application | ||||
""" | ||||
resource = request.context.resource | ||||
r153 | form = forms.CheckPasswordForm( | |||
MultiDict(request.unsafe_json_body), csrf_context=request | ||||
) | ||||
r0 | form.password.user = request.user | |||
if form.validate(): | ||||
resource.api_key = resource.generate_api_key() | ||||
resource.public_key = resource.generate_api_key() | ||||
r153 | msg = "API keys regenerated - please update your application config." | |||
r0 | request.session.flash(_(msg)) | |||
else: | ||||
return HTTPUnprocessableEntity(body=form.errors_json) | ||||
r153 | if request.has_permission("edit"): | |||
r0 | include_sensitive_info = True | |||
resource_dict = resource.get_dict( | ||||
include_perms=include_sensitive_info, | ||||
r153 | include_processing_rules=include_sensitive_info, | |||
) | ||||
r0 | return resource_dict | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=delete_resource", | ||||
request_method="PATCH", | ||||
renderer="json", | ||||
permission="delete", | ||||
) | ||||
r0 | def application_remove(request): | |||
""" | ||||
Removes application resources | ||||
""" | ||||
resource = request.context.resource | ||||
# we need polymorphic object here, to properly launch sqlalchemy events | ||||
resource = ApplicationService.by_id(resource.resource_id) | ||||
r153 | form = forms.CheckPasswordForm( | |||
MultiDict(request.safe_json_body or {}), csrf_context=request | ||||
) | ||||
r0 | form.password.user = request.user | |||
if form.validate(): | ||||
DBSession.delete(resource) | ||||
r153 | request.session.flash(_("Application removed")) | |||
r0 | else: | |||
return HTTPUnprocessableEntity(body=form.errors_json) | ||||
return True | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=owner", | ||||
request_method="PATCH", | ||||
renderer="json", | ||||
permission="delete", | ||||
) | ||||
r0 | def application_ownership_transfer(request): | |||
""" | ||||
Allows application owner to transfer application ownership to other user | ||||
""" | ||||
resource = request.context.resource | ||||
form = forms.ChangeApplicationOwnerForm( | ||||
r153 | MultiDict(request.safe_json_body or {}), csrf_context=request | |||
) | ||||
r0 | form.password.user = request.user | |||
if form.validate(): | ||||
r135 | user = UserService.by_user_name(form.user_name.data) | |||
r0 | user.resources.append(resource) | |||
# remove integrations to not leak security data of external applications | ||||
for integration in resource.integrations[:]: | ||||
resource.integrations.remove(integration) | ||||
r153 | request.session.flash(_("Application transfered")) | |||
r0 | else: | |||
return HTTPUnprocessableEntity(body=form.errors_json) | ||||
return True | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=postprocessing_rules", | ||||
renderer="json", | ||||
request_method="POST", | ||||
permission="edit", | ||||
) | ||||
r0 | def applications_postprocess_POST(request): | |||
""" | ||||
Creates new postprocessing rules for applications | ||||
""" | ||||
resource = request.context.resource | ||||
conf = ApplicationPostprocessConf() | ||||
r153 | conf.do = "postprocess" | |||
conf.new_value = "1" | ||||
r0 | resource.postprocess_conf.append(conf) | |||
DBSession.flush() | ||||
return conf.get_dict() | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=postprocessing_rules", | ||||
renderer="json", | ||||
request_method="PATCH", | ||||
permission="edit", | ||||
) | ||||
r0 | def applications_postprocess_PATCH(request): | |||
""" | ||||
Creates new postprocessing rules for applications | ||||
""" | ||||
json_body = request.unsafe_json_body | ||||
r153 | schema = build_rule_schema(json_body["rule"], REPORT_TYPE_MATRIX) | |||
r0 | try: | |||
r153 | schema.deserialize(json_body["rule"]) | |||
r0 | except colander.Invalid as exc: | |||
return HTTPUnprocessableEntity(body=json.dumps(exc.asdict())) | ||||
resource = request.context.resource | ||||
conf = ApplicationPostprocessConfService.by_pkey_and_resource_id( | ||||
r153 | json_body["pkey"], resource.resource_id | |||
) | ||||
conf.rule = request.unsafe_json_body["rule"] | ||||
r0 | # for now hardcode int since we dont support anything else so far | |||
r153 | conf.new_value = int(request.unsafe_json_body["new_value"]) | |||
r0 | return conf.get_dict() | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=postprocessing_rules", | ||||
renderer="json", | ||||
request_method="DELETE", | ||||
permission="edit", | ||||
) | ||||
r0 | def applications_postprocess_DELETE(request): | |||
""" | ||||
Removes application postprocessing rules | ||||
""" | ||||
form = forms.ReactorForm(request.POST, csrf_context=request) | ||||
resource = request.context.resource | ||||
if form.validate(): | ||||
for postprocess_conf in resource.postprocess_conf: | ||||
r153 | if postprocess_conf.pkey == int(request.GET["pkey"]): | |||
r0 | # remove rule | |||
DBSession.delete(postprocess_conf) | ||||
return True | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=report_graphs", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
@view_config( | ||||
route_name="applications_property", | ||||
match_param="key=slow_report_graphs", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def get_application_report_stats(request): | |||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.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(hours=1) | |||
r153 | filter_settings["start_date"] = filter_settings["end_date"] - delta | |||
r0 | ||||
result = ReportGroupService.get_report_stats(request, filter_settings) | ||||
return result | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=metrics_graphs", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def metrics_graphs(request): | |||
""" | ||||
Handles metric dashboard graphs | ||||
Returns information for time/tier breakdown | ||||
""" | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
r0 | ||||
r153 | 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 | ||||
delta = timedelta(hours=1) | ||||
r153 | if not filter_settings.get("start_date"): | |||
filter_settings["start_date"] = filter_settings["end_date"] - delta | ||||
if filter_settings["end_date"] <= filter_settings["start_date"]: | ||||
filter_settings["end_date"] = filter_settings["start_date"] | ||||
r0 | ||||
r153 | delta = filter_settings["end_date"] - filter_settings["start_date"] | |||
if delta < h.time_deltas.get("12h")["delta"]: | ||||
r0 | divide_by_min = 1 | |||
r153 | elif delta <= h.time_deltas.get("3d")["delta"]: | |||
r0 | divide_by_min = 5.0 | |||
r153 | elif delta >= h.time_deltas.get("2w")["delta"]: | |||
r0 | divide_by_min = 60.0 * 24 | |||
else: | ||||
divide_by_min = 60.0 | ||||
r153 | results = RequestMetricService.get_metrics_stats(request, filter_settings) | |||
r0 | # because requests are PER SECOND / we divide 1 min stats by 60 | |||
# requests are normalized to 1 min average | ||||
# results are average seconds time spent per request in specific area | ||||
for point in results: | ||||
r153 | if point["requests"]: | |||
point["main"] = ( | ||||
point["main"] | ||||
- point["sql"] | ||||
- point["nosql"] | ||||
- point["remote"] | ||||
- point["tmpl"] | ||||
- point["custom"] | ||||
) / point["requests"] | ||||
point["sql"] = point["sql"] / point["requests"] | ||||
point["nosql"] = point["nosql"] / point["requests"] | ||||
point["remote"] = point["remote"] / point["requests"] | ||||
point["tmpl"] = point["tmpl"] / point["requests"] | ||||
point["custom"] = point["custom"] / point["requests"] | ||||
point["requests_2"] = point["requests"] / 60.0 / divide_by_min | ||||
selected_types = ["main", "sql", "nosql", "remote", "tmpl", "custom"] | ||||
r0 | ||||
for point in results: | ||||
for stat_type in selected_types: | ||||
point[stat_type] = round(point.get(stat_type, 0), 3) | ||||
return results | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=response_graphs", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def response_graphs(request): | |||
""" | ||||
Handles dashboard infomation for avg. response time split by today, | ||||
2 days ago and week ago | ||||
""" | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
r0 | ||||
r153 | 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 | ||||
delta = timedelta(hours=1) | ||||
r153 | if not filter_settings.get("start_date"): | |||
filter_settings["start_date"] = filter_settings["end_date"] - delta | ||||
r0 | ||||
r153 | result_now = RequestMetricService.get_metrics_stats(request, filter_settings) | |||
r0 | ||||
filter_settings_2d = filter_settings.copy() | ||||
r153 | filter_settings_2d["start_date"] = filter_settings["start_date"] - timedelta(days=2) | |||
filter_settings_2d["end_date"] = filter_settings["end_date"] - timedelta(days=2) | ||||
result_2d = RequestMetricService.get_metrics_stats(request, filter_settings_2d) | ||||
r0 | ||||
filter_settings_7d = filter_settings.copy() | ||||
r153 | filter_settings_7d["start_date"] = filter_settings["start_date"] - timedelta(days=7) | |||
filter_settings_7d["end_date"] = filter_settings["end_date"] - timedelta(days=7) | ||||
result_7d = RequestMetricService.get_metrics_stats(request, filter_settings_7d) | ||||
r0 | ||||
plot_data = [] | ||||
for item in result_now: | ||||
r153 | point = {"x": item["x"], "today": 0, "days_ago_2": 0, "days_ago_7": 0} | |||
if item["requests"]: | ||||
point["today"] = round(item["main"] / item["requests"], 3) | ||||
r0 | plot_data.append(point) | |||
r153 | for i, item in enumerate(result_2d[: len(plot_data)]): | |||
plot_data[i]["days_ago_2"] = 0 | ||||
r0 | point = result_2d[i] | |||
r153 | if point["requests"]: | |||
plot_data[i]["days_ago_2"] = round(point["main"] / point["requests"], 3) | ||||
r0 | ||||
r153 | for i, item in enumerate(result_7d[: len(plot_data)]): | |||
plot_data[i]["days_ago_7"] = 0 | ||||
r0 | point = result_7d[i] | |||
r153 | if point["requests"]: | |||
plot_data[i]["days_ago_7"] = round(point["main"] / point["requests"], 3) | ||||
r0 | ||||
return plot_data | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=requests_graphs", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def requests_graphs(request): | |||
""" | ||||
Handles dashboard infomation for avg. response time split by today, | ||||
2 days ago and week ago | ||||
""" | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
r0 | ||||
r153 | 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 | ||||
delta = timedelta(hours=1) | ||||
r153 | if not filter_settings.get("start_date"): | |||
filter_settings["start_date"] = filter_settings["end_date"] - delta | ||||
result_now = RequestMetricService.get_metrics_stats(request, filter_settings) | ||||
delta = filter_settings["end_date"] - filter_settings["start_date"] | ||||
if delta < h.time_deltas.get("12h")["delta"]: | ||||
seconds = h.time_deltas["1m"]["minutes"] * 60.0 | ||||
elif delta <= h.time_deltas.get("3d")["delta"]: | ||||
seconds = h.time_deltas["5m"]["minutes"] * 60.0 | ||||
elif delta >= h.time_deltas.get("2w")["delta"]: | ||||
seconds = h.time_deltas["24h"]["minutes"] * 60.0 | ||||
r0 | else: | |||
r153 | seconds = h.time_deltas["1h"]["minutes"] * 60.0 | |||
r0 | ||||
for item in result_now: | ||||
r153 | if item["requests"]: | |||
item["requests"] = round(item["requests"] / seconds, 3) | ||||
r0 | return result_now | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=apdex_stats", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def get_apdex_stats(request): | |||
""" | ||||
Returns information and calculates APDEX score per server for dashboard | ||||
server information (upper right stats boxes) | ||||
""" | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
r0 | # make sure we have only one resource here to don't produce | |||
# weird results when we have wrong app in app selector | ||||
r153 | filter_settings["resource"] = [filter_settings["resource"][0]] | |||
r0 | ||||
r153 | 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 | ||||
delta = timedelta(hours=1) | ||||
r153 | if not filter_settings.get("start_date"): | |||
filter_settings["start_date"] = filter_settings["end_date"] - delta | ||||
r0 | ||||
return RequestMetricService.get_apdex_stats(request, filter_settings) | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=slow_calls", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def get_slow_calls(request): | |||
""" | ||||
Returns information for time consuming calls in specific time interval | ||||
""" | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
r0 | ||||
r153 | 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 | ||||
delta = timedelta(hours=1) | ||||
r153 | if not filter_settings.get("start_date"): | |||
filter_settings["start_date"] = filter_settings["end_date"] - delta | ||||
r0 | ||||
return SlowCallService.get_time_consuming_calls(request, filter_settings) | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=requests_breakdown", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def get_requests_breakdown(request): | |||
""" | ||||
Used on dashboard to get information which views are most used in | ||||
a time interval | ||||
""" | ||||
query_params = request.GET.mixed() | ||||
r153 | query_params["resource"] = (request.context.resource.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(hours=1) | |||
r153 | filter_settings["start_date"] = filter_settings["end_date"] - delta | |||
r0 | ||||
r153 | series = RequestMetricService.get_requests_breakdown(request, filter_settings) | |||
r0 | ||||
results = [] | ||||
for row in series: | ||||
r153 | d_row = { | |||
"avg_response": round(row["main"] / row["requests"], 3), | ||||
"requests": row["requests"], | ||||
"main": row["main"], | ||||
"view_name": row["key"], | ||||
"latest_details": row["latest_details"], | ||||
"percentage": round(row["percentage"] * 100, 1), | ||||
} | ||||
r0 | ||||
results.append(d_row) | ||||
return results | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=trending_reports", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def trending_reports(request): | |||
""" | ||||
Returns exception/slow reports trending for specific time interval | ||||
""" | ||||
query_params = request.GET.mixed().copy() | ||||
# pop report type to rewrite it to tag later | ||||
r153 | report_type = query_params.pop("report_type", None) | |||
r0 | if report_type: | |||
r153 | query_params["type"] = report_type | |||
r0 | ||||
r153 | query_params["resource"] = (request.context.resource.resource_id,) | |||
r0 | ||||
r153 | filter_settings = build_filter_settings_from_query_dict(request, query_params) | |||
r0 | ||||
r153 | 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(hours=1) | |||
r153 | filter_settings["start_date"] = filter_settings["end_date"] - delta | |||
r0 | ||||
results = ReportGroupService.get_trending(request, filter_settings) | ||||
trending = [] | ||||
for occurences, group in results: | ||||
report_group = group.get_dict(request) | ||||
# show the occurences in time range instead of global ones | ||||
r153 | report_group["occurences"] = occurences | |||
r0 | trending.append(report_group) | |||
return trending | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=integrations", | ||||
renderer="json", | ||||
permission="view", | ||||
) | ||||
r0 | def integrations(request): | |||
""" | ||||
Integration list for given application | ||||
""" | ||||
application = request.context.resource | ||||
r153 | return {"resource": application} | |||
r0 | ||||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=user_permissions", | ||||
renderer="json", | ||||
permission="owner", | ||||
request_method="POST", | ||||
) | ||||
r0 | def user_resource_permission_create(request): | |||
""" | ||||
Set new permissions for user for a resource | ||||
""" | ||||
resource = request.context.resource | ||||
r153 | user_name = request.unsafe_json_body.get("user_name") | |||
r135 | user = UserService.by_user_name(user_name) | |||
r0 | if not user: | |||
r135 | user = UserService.by_email(user_name) | |||
r0 | if not user: | |||
return False | ||||
r153 | for perm_name in request.unsafe_json_body.get("permissions", []): | |||
r135 | permission = UserResourcePermissionService.by_resource_user_and_perm( | |||
r153 | user.id, perm_name, resource.resource_id | |||
) | ||||
r0 | if not permission: | |||
r153 | permission = UserResourcePermission(perm_name=perm_name, user_id=user.id) | |||
r0 | resource.user_permissions.append(permission) | |||
DBSession.flush() | ||||
r153 | perms = [ | |||
p.perm_name | ||||
for p in ResourceService.perms_for_user(resource, user) | ||||
if p.type == "user" | ||||
] | ||||
result = {"user_name": user.user_name, "permissions": list(set(perms))} | ||||
r0 | return result | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=user_permissions", | ||||
renderer="json", | ||||
permission="owner", | ||||
request_method="DELETE", | ||||
) | ||||
r0 | def user_resource_permission_delete(request): | |||
""" | ||||
Removes user permission from specific resource | ||||
""" | ||||
resource = request.context.resource | ||||
r153 | user = UserService.by_user_name(request.GET.get("user_name")) | |||
r0 | if not user: | |||
return False | ||||
r153 | for perm_name in request.GET.getall("permissions"): | |||
r135 | permission = UserResourcePermissionService.by_resource_user_and_perm( | |||
r153 | user.id, perm_name, resource.resource_id | |||
) | ||||
r0 | resource.user_permissions.remove(permission) | |||
DBSession.flush() | ||||
r153 | perms = [ | |||
p.perm_name | ||||
for p in ResourceService.perms_for_user(resource, user) | ||||
if p.type == "user" | ||||
] | ||||
result = {"user_name": user.user_name, "permissions": list(set(perms))} | ||||
r0 | return result | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=group_permissions", | ||||
renderer="json", | ||||
permission="owner", | ||||
request_method="POST", | ||||
) | ||||
r0 | def group_resource_permission_create(request): | |||
""" | ||||
Set new permissions for group for a resource | ||||
""" | ||||
resource = request.context.resource | ||||
r153 | group = GroupService.by_id(request.unsafe_json_body.get("group_id")) | |||
r0 | if not group: | |||
return False | ||||
r153 | for perm_name in request.unsafe_json_body.get("permissions", []): | |||
r0 | permission = GroupResourcePermissionService.by_resource_group_and_perm( | |||
r153 | group.id, perm_name, resource.resource_id | |||
) | ||||
r0 | if not permission: | |||
r153 | permission = GroupResourcePermission(perm_name=perm_name, group_id=group.id) | |||
r0 | resource.group_permissions.append(permission) | |||
DBSession.flush() | ||||
r135 | perm_tuples = ResourceService.groups_for_perm( | |||
r153 | resource, ANY_PERMISSION, limit_group_permissions=True, group_ids=[group.id] | |||
) | ||||
perms = [p.perm_name for p in perm_tuples if p.type == "group"] | ||||
result = {"group": group.get_dict(), "permissions": list(set(perms))} | ||||
r0 | return result | |||
r153 | @view_config( | |||
route_name="applications_property", | ||||
match_param="key=group_permissions", | ||||
renderer="json", | ||||
permission="owner", | ||||
request_method="DELETE", | ||||
) | ||||
r0 | def group_resource_permission_delete(request): | |||
""" | ||||
Removes group permission from specific resource | ||||
""" | ||||
form = forms.ReactorForm(request.POST, csrf_context=request) | ||||
form.validate() | ||||
resource = request.context.resource | ||||
r153 | group = GroupService.by_id(request.GET.get("group_id")) | |||
r0 | if not group: | |||
return False | ||||
r153 | for perm_name in request.GET.getall("permissions"): | |||
r0 | permission = GroupResourcePermissionService.by_resource_group_and_perm( | |||
r153 | group.id, perm_name, resource.resource_id | |||
) | ||||
r0 | resource.group_permissions.remove(permission) | |||
DBSession.flush() | ||||
r135 | perm_tuples = ResourceService.groups_for_perm( | |||
r153 | resource, ANY_PERMISSION, limit_group_permissions=True, group_ids=[group.id] | |||
) | ||||
perms = [p.perm_name for p in perm_tuples if p.type == "group"] | ||||
result = {"group": group.get_dict(), "permissions": list(set(perms))} | ||||
r0 | return result | |||