user.py
166 lines
| 6.0 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 | ||||
import pyramid_mailer | ||||
import pyramid.renderers | ||||
import sqlalchemy as sa | ||||
from collections import namedtuple | ||||
from datetime import datetime | ||||
r135 | from ziggurat_foundations.models.services.user import UserService | |||
r0 | from appenlight.lib.rule import Rule | |||
from appenlight.models import get_db_session | ||||
from appenlight.models.integrations import IntegrationException | ||||
from appenlight.models.report import REPORT_TYPE_MATRIX | ||||
from appenlight.models.user import User | ||||
from paginate_sqlalchemy import SqlalchemyOrmPage | ||||
from pyramid.threadlocal import get_current_registry | ||||
log = logging.getLogger(__name__) | ||||
r153 | GroupOccurence = namedtuple("GroupOccurence", ["occurences", "group"]) | |||
r0 | ||||
r135 | class UserService(UserService): | |||
r0 | @classmethod | |||
def all(cls, db_session=None): | ||||
return get_db_session(db_session).query(User).order_by(User.user_name) | ||||
@classmethod | ||||
r153 | def send_email( | |||
cls, request, recipients, variables, template, immediately=False, silent=False | ||||
): | ||||
r0 | html = pyramid.renderers.render(template, variables, request) | |||
r153 | title = variables.get("email_title", variables.get("title", "No Title")) | |||
title = title.replace("\r", "").replace("\n", "") | ||||
r0 | sender = "{} <{}>".format( | |||
r153 | request.registry.settings["mailing.from_name"], | |||
request.registry.settings["mailing.from_email"], | ||||
) | ||||
r0 | message = pyramid_mailer.message.Message( | |||
r153 | subject=title, sender=sender, recipients=recipients, html=html | |||
) | ||||
r0 | if immediately: | |||
try: | ||||
request.registry.mailer.send_immediately(message) | ||||
except Exception as e: | ||||
r153 | log.warning("Exception %s" % e) | |||
r0 | if not silent: | |||
raise | ||||
else: | ||||
request.registry.mailer.send(message) | ||||
@classmethod | ||||
r153 | def get_paginator( | |||
cls, | ||||
page=1, | ||||
item_count=None, | ||||
items_per_page=50, | ||||
order_by=None, | ||||
filter_settings=None, | ||||
exclude_columns=None, | ||||
db_session=None, | ||||
): | ||||
r0 | registry = get_current_registry() | |||
if not exclude_columns: | ||||
exclude_columns = [] | ||||
if not filter_settings: | ||||
filter_settings = {} | ||||
db_session = get_db_session(db_session) | ||||
q = db_session.query(User) | ||||
r153 | if filter_settings.get("order_col"): | |||
order_col = filter_settings.get("order_col") | ||||
if filter_settings.get("order_dir") == "dsc": | ||||
sort_on = "desc" | ||||
r0 | else: | |||
r153 | sort_on = "asc" | |||
r0 | q = q.order_by(getattr(sa, sort_on)(getattr(User, order_col))) | |||
else: | ||||
q = q.order_by(sa.desc(User.registered_date)) | ||||
# remove urlgen or it never caches count | ||||
cache_params = dict(filter_settings) | ||||
r153 | cache_params.pop("url", None) | |||
cache_params.pop("url_maker", None) | ||||
r0 | ||||
@registry.cache_regions.redis_min_5.cache_on_arguments() | ||||
def estimate_users(cache_key): | ||||
o_q = q.order_by(False) | ||||
return o_q.count() | ||||
item_count = estimate_users(cache_params) | ||||
# if the number of pages is low we may want to invalidate the count to | ||||
# provide 'real time' update - use case - | ||||
# errors just started to flow in | ||||
if item_count < 1000: | ||||
item_count = estimate_users.refresh(cache_params) | ||||
r153 | paginator = SqlalchemyOrmPage( | |||
q, | ||||
page=page, | ||||
item_count=item_count, | ||||
items_per_page=items_per_page, | ||||
**filter_settings | ||||
) | ||||
r0 | return paginator | |||
@classmethod | ||||
def get_valid_channels(cls, user): | ||||
r153 | return [channel for channel in user.alert_channels if channel.channel_validated] | |||
r0 | ||||
@classmethod | ||||
r153 | def report_notify( | |||
cls, user, request, application, report_groups, occurence_dict, db_session=None | ||||
): | ||||
r0 | db_session = get_db_session(db_session) | |||
if not report_groups: | ||||
return True | ||||
r21 | since_when = datetime.utcnow() | |||
r0 | for channel in cls.get_valid_channels(user): | |||
confirmed_groups = [] | ||||
for group in report_groups: | ||||
occurences = occurence_dict.get(group.id, 1) | ||||
for action in channel.channel_actions: | ||||
not_matched = ( | ||||
r153 | action.resource_id | |||
and action.resource_id != application.resource_id | ||||
) | ||||
if action.type != "report" or not_matched: | ||||
r0 | continue | |||
r153 | should_notify = action.action == "always" or not group.notified | |||
r0 | rule_obj = Rule(action.rule, REPORT_TYPE_MATRIX) | |||
report_dict = group.get_report().get_dict(request) | ||||
if rule_obj.match(report_dict) and should_notify: | ||||
item = GroupOccurence(occurences, group) | ||||
if item not in confirmed_groups: | ||||
confirmed_groups.append(item) | ||||
# send individual reports | ||||
total_confirmed = len(confirmed_groups) | ||||
if not total_confirmed: | ||||
continue | ||||
try: | ||||
r153 | channel.notify_reports( | |||
resource=application, | ||||
user=user, | ||||
request=request, | ||||
since_when=since_when, | ||||
reports=confirmed_groups, | ||||
) | ||||
r0 | except IntegrationException as e: | |||
r153 | log.warning("%s" % e) | |||