|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
|
|
|
#
|
|
|
# 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
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# 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.
|
|
|
|
|
|
import wtforms
|
|
|
import formencode
|
|
|
import re
|
|
|
import pyramid.threadlocal
|
|
|
import datetime
|
|
|
import appenlight.lib.helpers as h
|
|
|
|
|
|
from ziggurat_foundations.models.services.user import UserService
|
|
|
from ziggurat_foundations.models.services.group import GroupService
|
|
|
from appenlight.models import DBSession
|
|
|
from appenlight.models.alert_channel import AlertChannel
|
|
|
from appenlight.models.integrations import IntegrationException
|
|
|
from appenlight.models.integrations.campfire import CampfireIntegration
|
|
|
from appenlight.models.integrations.bitbucket import BitbucketIntegration
|
|
|
from appenlight.models.integrations.github import GithubIntegration
|
|
|
from appenlight.models.integrations.flowdock import FlowdockIntegration
|
|
|
from appenlight.models.integrations.hipchat import HipchatIntegration
|
|
|
from appenlight.models.integrations.jira import JiraClient
|
|
|
from appenlight.models.integrations.slack import SlackIntegration
|
|
|
from appenlight.lib.ext_json import json
|
|
|
from wtforms.ext.csrf.form import SecureForm
|
|
|
from wtforms.compat import iteritems
|
|
|
from collections import defaultdict
|
|
|
|
|
|
_ = str
|
|
|
|
|
|
strip_filter = lambda x: x.strip() if x else None
|
|
|
uppercase_filter = lambda x: x.upper() if x else None
|
|
|
|
|
|
FALSE_VALUES = ("false", "", False, None)
|
|
|
|
|
|
|
|
|
class CSRFException(Exception):
|
|
|
pass
|
|
|
|
|
|
|
|
|
class ReactorForm(SecureForm):
|
|
|
def __init__(self, formdata=None, obj=None, prefix="", csrf_context=None, **kwargs):
|
|
|
super(ReactorForm, self).__init__(
|
|
|
formdata=formdata,
|
|
|
obj=obj,
|
|
|
prefix=prefix,
|
|
|
csrf_context=csrf_context,
|
|
|
**kwargs
|
|
|
)
|
|
|
self._csrf_context = csrf_context
|
|
|
|
|
|
def generate_csrf_token(self, csrf_context):
|
|
|
return csrf_context.session.get_csrf_token()
|
|
|
|
|
|
def validate_csrf_token(self, field):
|
|
|
request = self._csrf_context or pyramid.threadlocal.get_current_request()
|
|
|
is_from_auth_token = "auth:auth_token" in request.effective_principals
|
|
|
if is_from_auth_token:
|
|
|
return True
|
|
|
|
|
|
if field.data != field.current_token:
|
|
|
# try to save the day by using token from angular
|
|
|
if request.headers.get("X-XSRF-TOKEN") != field.current_token:
|
|
|
raise CSRFException("Invalid CSRF token")
|
|
|
|
|
|
@property
|
|
|
def errors_dict(self):
|
|
|
r_dict = defaultdict(list)
|
|
|
for k, errors in self.errors.items():
|
|
|
r_dict[k].extend([str(e) for e in errors])
|
|
|
return r_dict
|
|
|
|
|
|
@property
|
|
|
def errors_json(self):
|
|
|
return json.dumps(self.errors_dict)
|
|
|
|
|
|
def populate_obj(self, obj, ignore_none=False):
|
|
|
"""
|
|
|
Populates the attributes of the passed `obj` with data from the form's
|
|
|
fields.
|
|
|
|
|
|
:note: This is a destructive operation; Any attribute with the same name
|
|
|
as a field will be overridden. Use with caution.
|
|
|
"""
|
|
|
if ignore_none:
|
|
|
for name, field in iteritems(self._fields):
|
|
|
if field.data is not None:
|
|
|
field.populate_obj(obj, name)
|
|
|
else:
|
|
|
for name, field in iteritems(self._fields):
|
|
|
field.populate_obj(obj, name)
|
|
|
|
|
|
css_classes = {}
|
|
|
ignore_labels = {}
|
|
|
|
|
|
|
|
|
class SignInForm(ReactorForm):
|
|
|
came_from = wtforms.HiddenField()
|
|
|
sign_in_user_name = wtforms.StringField(_("User Name"))
|
|
|
sign_in_user_password = wtforms.PasswordField(_("Password"))
|
|
|
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
html_attrs = {
|
|
|
"sign_in_user_name": {"placeholder": "Your login"},
|
|
|
"sign_in_user_password": {"placeholder": "Your password"},
|
|
|
}
|
|
|
|
|
|
|
|
|
from wtforms.widgets import html_params, HTMLString
|
|
|
|
|
|
|
|
|
def select_multi_checkbox(field, ul_class="set", **kwargs):
|
|
|
"""Render a multi-checkbox widget"""
|
|
|
kwargs.setdefault("type", "checkbox")
|
|
|
field_id = kwargs.pop("id", field.id)
|
|
|
html = ["<ul %s>" % html_params(id=field_id, class_=ul_class)]
|
|
|
for value, label, checked in field.iter_choices():
|
|
|
choice_id = "%s-%s" % (field_id, value)
|
|
|
options = dict(kwargs, name=field.name, value=value, id=choice_id)
|
|
|
if checked:
|
|
|
options["checked"] = "checked"
|
|
|
html.append("<li><input %s /> " % html_params(**options))
|
|
|
html.append('<label for="%s">%s</label></li>' % (choice_id, label))
|
|
|
html.append("</ul>")
|
|
|
return HTMLString("".join(html))
|
|
|
|
|
|
|
|
|
def button_widget(field, button_cls="ButtonField btn btn-default", **kwargs):
|
|
|
"""Render a button widget"""
|
|
|
kwargs.setdefault("type", "button")
|
|
|
field_id = kwargs.pop("id", field.id)
|
|
|
kwargs.setdefault("value", field.label.text)
|
|
|
html = [
|
|
|
"<button %s>%s</button>"
|
|
|
% (html_params(id=field_id, class_=button_cls), kwargs["value"])
|
|
|
]
|
|
|
return HTMLString("".join(html))
|
|
|
|
|
|
|
|
|
def clean_whitespace(value):
|
|
|
if value:
|
|
|
return value.strip()
|
|
|
return value
|
|
|
|
|
|
|
|
|
def found_username_validator(form, field):
|
|
|
user = UserService.by_user_name(field.data)
|
|
|
# sets user to recover in email validator
|
|
|
form.field_user = user
|
|
|
if not user:
|
|
|
raise wtforms.ValidationError("This username does not exist")
|
|
|
|
|
|
|
|
|
def found_username_email_validator(form, field):
|
|
|
user = UserService.by_email(field.data)
|
|
|
if not user:
|
|
|
raise wtforms.ValidationError("Email is incorrect")
|
|
|
|
|
|
|
|
|
def unique_username_validator(form, field):
|
|
|
user = UserService.by_user_name(field.data)
|
|
|
if user:
|
|
|
raise wtforms.ValidationError("This username already exists in system")
|
|
|
|
|
|
|
|
|
def unique_groupname_validator(form, field):
|
|
|
group = GroupService.by_group_name(field.data)
|
|
|
mod_group = getattr(form, "_modified_group", None)
|
|
|
if group and (not mod_group or mod_group.id != group.id):
|
|
|
raise wtforms.ValidationError("This group name already exists in system")
|
|
|
|
|
|
|
|
|
def unique_email_validator(form, field):
|
|
|
user = UserService.by_email(field.data)
|
|
|
if user:
|
|
|
raise wtforms.ValidationError("This email already exists in system")
|
|
|
|
|
|
|
|
|
def email_validator(form, field):
|
|
|
validator = formencode.validators.Email()
|
|
|
try:
|
|
|
validator.to_python(field.data)
|
|
|
except formencode.Invalid as e:
|
|
|
raise wtforms.ValidationError(e)
|
|
|
|
|
|
|
|
|
def unique_alert_email_validator(form, field):
|
|
|
q = DBSession.query(AlertChannel)
|
|
|
q = q.filter(AlertChannel.channel_name == "email")
|
|
|
q = q.filter(AlertChannel.channel_value == field.data)
|
|
|
email = q.first()
|
|
|
if email:
|
|
|
raise wtforms.ValidationError("This email already exists in alert system")
|
|
|
|
|
|
|
|
|
def blocked_email_validator(form, field):
|
|
|
blocked_emails = [
|
|
|
"goood-mail.org",
|
|
|
"shoeonlineblog.com",
|
|
|
"louboutinemart.com",
|
|
|
"guccibagshere.com",
|
|
|
"nikeshoesoutletforsale.com",
|
|
|
]
|
|
|
data = field.data or ""
|
|
|
domain = data.split("@")[-1]
|
|
|
if domain in blocked_emails:
|
|
|
raise wtforms.ValidationError("Don't spam")
|
|
|
|
|
|
|
|
|
def old_password_validator(form, field):
|
|
|
if not UserService.check_password(field.user, field.data or ""):
|
|
|
raise wtforms.ValidationError("You need to enter correct password")
|
|
|
|
|
|
|
|
|
class UserRegisterForm(ReactorForm):
|
|
|
user_name = wtforms.StringField(
|
|
|
_("User Name"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=2, max=30),
|
|
|
wtforms.validators.Regexp(
|
|
|
re.compile(r"^[\.\w-]+$", re.UNICODE), message="Invalid characters used"
|
|
|
),
|
|
|
unique_username_validator,
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
|
|
|
user_password = wtforms.PasswordField(
|
|
|
_("User Password"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=4),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
|
|
|
email = wtforms.StringField(
|
|
|
_("Email Address"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
email_validator,
|
|
|
unique_email_validator,
|
|
|
blocked_email_validator,
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
first_name = wtforms.HiddenField(_("First Name"))
|
|
|
last_name = wtforms.HiddenField(_("Last Name"))
|
|
|
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
html_attrs = {
|
|
|
"user_name": {"placeholder": "Your login"},
|
|
|
"user_password": {"placeholder": "Your password"},
|
|
|
"email": {"placeholder": "Your email"},
|
|
|
}
|
|
|
|
|
|
|
|
|
class UserCreateForm(UserRegisterForm):
|
|
|
status = wtforms.BooleanField("User status", false_values=FALSE_VALUES)
|
|
|
|
|
|
|
|
|
class UserUpdateForm(UserCreateForm):
|
|
|
user_name = None
|
|
|
user_password = wtforms.PasswordField(
|
|
|
_("User Password"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.Length(min=4), wtforms.validators.Optional()],
|
|
|
)
|
|
|
email = wtforms.StringField(
|
|
|
_("Email Address"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[email_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
|
|
|
class LostPasswordForm(ReactorForm):
|
|
|
email = wtforms.StringField(
|
|
|
_("Email Address"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
email_validator,
|
|
|
found_username_email_validator,
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
|
|
|
submit = wtforms.SubmitField(_("Reset password"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class ChangePasswordForm(ReactorForm):
|
|
|
old_password = wtforms.PasswordField(
|
|
|
"Old Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[old_password_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
new_password = wtforms.PasswordField(
|
|
|
"New Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=4),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
new_password_confirm = wtforms.PasswordField(
|
|
|
"Confirm Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.EqualTo("new_password"),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
submit = wtforms.SubmitField("Change Password")
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class CheckPasswordForm(ReactorForm):
|
|
|
password = wtforms.PasswordField(
|
|
|
"Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[old_password_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
|
|
|
class NewPasswordForm(ReactorForm):
|
|
|
new_password = wtforms.PasswordField(
|
|
|
"New Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=4),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
new_password_confirm = wtforms.PasswordField(
|
|
|
"Confirm Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.EqualTo("new_password"),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
submit = wtforms.SubmitField("Set Password")
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class CORSTextAreaField(wtforms.StringField):
|
|
|
"""
|
|
|
This field represents an HTML ``<textarea>`` and can be used to take
|
|
|
multi-line input.
|
|
|
"""
|
|
|
|
|
|
widget = wtforms.widgets.TextArea()
|
|
|
|
|
|
def process_formdata(self, valuelist):
|
|
|
self.data = []
|
|
|
if valuelist:
|
|
|
data = [x.strip() for x in valuelist[0].split("\n")]
|
|
|
for d in data:
|
|
|
if not d:
|
|
|
continue
|
|
|
if d.startswith("www."):
|
|
|
d = d[4:]
|
|
|
if data:
|
|
|
self.data.append(d)
|
|
|
else:
|
|
|
self.data = []
|
|
|
self.data = "\n".join(self.data)
|
|
|
|
|
|
|
|
|
class ApplicationCreateForm(ReactorForm):
|
|
|
resource_name = wtforms.StringField(
|
|
|
_("Application name"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=1),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
|
|
|
domains = CORSTextAreaField(
|
|
|
_("Domain names for CORS headers "),
|
|
|
validators=[wtforms.validators.Length(min=1), wtforms.validators.Optional()],
|
|
|
description="Required for Javascript error "
|
|
|
"tracking (one line one domain, skip http:// part)",
|
|
|
)
|
|
|
|
|
|
submit = wtforms.SubmitField(_("Create Application"))
|
|
|
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
html_attrs = {
|
|
|
"resource_name": {"placeholder": "Application Name"},
|
|
|
"uptime_url": {"placeholder": "http://somedomain.com"},
|
|
|
}
|
|
|
|
|
|
|
|
|
class ApplicationUpdateForm(ApplicationCreateForm):
|
|
|
default_grouping = wtforms.SelectField(
|
|
|
_("Default grouping for errors"),
|
|
|
choices=[
|
|
|
("url_type", "Error Type + location"),
|
|
|
("url_traceback", "Traceback + location"),
|
|
|
("traceback_server", "Traceback + Server"),
|
|
|
],
|
|
|
default="url_traceback",
|
|
|
)
|
|
|
|
|
|
error_report_threshold = wtforms.IntegerField(
|
|
|
_("Alert on error reports"),
|
|
|
validators=[
|
|
|
wtforms.validators.NumberRange(min=1),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
description="Application requires to send at least this amount of "
|
|
|
"error reports per minute to open alert",
|
|
|
)
|
|
|
|
|
|
slow_report_threshold = wtforms.IntegerField(
|
|
|
_("Alert on slow reports"),
|
|
|
validators=[
|
|
|
wtforms.validators.NumberRange(min=1),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
description="Application requires to send at least this amount of "
|
|
|
"slow reports per minute to open alert",
|
|
|
)
|
|
|
|
|
|
allow_permanent_storage = wtforms.BooleanField(
|
|
|
_("Permanent logs"),
|
|
|
false_values=FALSE_VALUES,
|
|
|
description=_("Allow permanent storage of logs in separate DB partitions"),
|
|
|
)
|
|
|
|
|
|
submit = wtforms.SubmitField(_("Create Application"))
|
|
|
|
|
|
|
|
|
class UserSearchSchemaForm(ReactorForm):
|
|
|
user_name = wtforms.StringField("User Name", filters=[strip_filter])
|
|
|
|
|
|
submit = wtforms.SubmitField(_("Search User"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
'<li class="user_exists"><span></span></li>'
|
|
|
|
|
|
|
|
|
class YesNoForm(ReactorForm):
|
|
|
no = wtforms.SubmitField("No", default="")
|
|
|
yes = wtforms.SubmitField("Yes", default="")
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
status_codes = [("", "All"), ("500", "500"), ("404", "404")]
|
|
|
|
|
|
priorities = [("", "All")]
|
|
|
for i in range(1, 11):
|
|
|
priorities.append((str(i), str(i)))
|
|
|
|
|
|
report_status_choices = [
|
|
|
("", "All"),
|
|
|
("never_reviewed", "Never revieved"),
|
|
|
("reviewed", "Revieved"),
|
|
|
("public", "Public"),
|
|
|
("fixed", "Fixed"),
|
|
|
]
|
|
|
|
|
|
|
|
|
class ReportBrowserForm(ReactorForm):
|
|
|
applications = wtforms.SelectMultipleField(
|
|
|
"Applications", widget=select_multi_checkbox
|
|
|
)
|
|
|
http_status = wtforms.SelectField("HTTP Status", choices=status_codes)
|
|
|
priority = wtforms.SelectField("Priority", choices=priorities, default="")
|
|
|
start_date = wtforms.DateField("Start Date")
|
|
|
end_date = wtforms.DateField("End Date")
|
|
|
error = wtforms.StringField("Error")
|
|
|
url_path = wtforms.StringField("URL Path")
|
|
|
url_domain = wtforms.StringField("URL Domain")
|
|
|
report_status = wtforms.SelectField(
|
|
|
"Report status", choices=report_status_choices, default=""
|
|
|
)
|
|
|
submit = wtforms.SubmitField(
|
|
|
'<span class="glyphicon glyphicon-search">' "</span> Filter results",
|
|
|
widget=button_widget,
|
|
|
)
|
|
|
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
slow_report_status_choices = [
|
|
|
("", "All"),
|
|
|
("never_reviewed", "Never revieved"),
|
|
|
("reviewed", "Revieved"),
|
|
|
("public", "Public"),
|
|
|
]
|
|
|
|
|
|
|
|
|
class BulkOperationForm(ReactorForm):
|
|
|
applications = wtforms.SelectField("Applications")
|
|
|
start_date = wtforms.DateField(
|
|
|
"Start Date",
|
|
|
default=lambda: datetime.datetime.utcnow() - datetime.timedelta(days=90),
|
|
|
)
|
|
|
end_date = wtforms.DateField("End Date")
|
|
|
confirm = wtforms.BooleanField(
|
|
|
"Confirm operation", validators=[wtforms.validators.DataRequired()]
|
|
|
)
|
|
|
|
|
|
|
|
|
class LogBrowserForm(ReactorForm):
|
|
|
applications = wtforms.SelectMultipleField(
|
|
|
"Applications", widget=select_multi_checkbox
|
|
|
)
|
|
|
start_date = wtforms.DateField("Start Date")
|
|
|
log_level = wtforms.StringField("Log level")
|
|
|
message = wtforms.StringField("Message")
|
|
|
namespace = wtforms.StringField("Namespace")
|
|
|
submit = wtforms.SubmitField(
|
|
|
'<span class="glyphicon glyphicon-search"></span> Filter results',
|
|
|
widget=button_widget,
|
|
|
)
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class CommentForm(ReactorForm):
|
|
|
body = wtforms.TextAreaField(
|
|
|
"Comment",
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=1),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
submit = wtforms.SubmitField("Comment")
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class EmailChannelCreateForm(ReactorForm):
|
|
|
email = wtforms.StringField(
|
|
|
_("Email Address"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
email_validator,
|
|
|
unique_alert_email_validator,
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
submit = wtforms.SubmitField("Add email channel")
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
def gen_user_profile_form():
|
|
|
class UserProfileForm(ReactorForm):
|
|
|
email = wtforms.StringField(
|
|
|
_("Email Address"),
|
|
|
validators=[email_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
first_name = wtforms.StringField(_("First Name"))
|
|
|
last_name = wtforms.StringField(_("Last Name"))
|
|
|
company_name = wtforms.StringField(_("Company Name"))
|
|
|
company_address = wtforms.TextAreaField(_("Company Address"))
|
|
|
zip_code = wtforms.StringField(_("ZIP code"))
|
|
|
city = wtforms.StringField(_("City"))
|
|
|
notifications = wtforms.BooleanField(
|
|
|
"Account notifications", false_values=FALSE_VALUES
|
|
|
)
|
|
|
submit = wtforms.SubmitField(_("Update Account"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
return UserProfileForm
|
|
|
|
|
|
|
|
|
class PurgeAppForm(ReactorForm):
|
|
|
resource_id = wtforms.HiddenField(
|
|
|
"App Id", validators=[wtforms.validators.DataRequired()]
|
|
|
)
|
|
|
days = wtforms.IntegerField("Days", validators=[wtforms.validators.DataRequired()])
|
|
|
password = wtforms.PasswordField(
|
|
|
"Admin Password",
|
|
|
validators=[old_password_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
submit = wtforms.SubmitField(_("Purge Data"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class IntegrationRepoForm(ReactorForm):
|
|
|
host_name = wtforms.StringField("Service Host", default="")
|
|
|
user_name = wtforms.StringField(
|
|
|
"User Name",
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.DataRequired(),
|
|
|
wtforms.validators.Length(min=1),
|
|
|
],
|
|
|
)
|
|
|
repo_name = wtforms.StringField(
|
|
|
"Repo Name",
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.DataRequired(),
|
|
|
wtforms.validators.Length(min=1),
|
|
|
],
|
|
|
)
|
|
|
|
|
|
|
|
|
class IntegrationBitbucketForm(IntegrationRepoForm):
|
|
|
host_name = wtforms.StringField("Service Host", default="https://bitbucket.org")
|
|
|
|
|
|
def validate_user_name(self, field):
|
|
|
try:
|
|
|
request = pyramid.threadlocal.get_current_request()
|
|
|
client = BitbucketIntegration.create_client(
|
|
|
request, self.user_name.data, self.repo_name.data
|
|
|
)
|
|
|
client.get_assignees()
|
|
|
except IntegrationException as e:
|
|
|
raise wtforms.validators.ValidationError(str(e))
|
|
|
|
|
|
|
|
|
class IntegrationGithubForm(IntegrationRepoForm):
|
|
|
host_name = wtforms.StringField("Service Host", default="https://github.com")
|
|
|
|
|
|
def validate_user_name(self, field):
|
|
|
try:
|
|
|
request = pyramid.threadlocal.get_current_request()
|
|
|
client = GithubIntegration.create_client(
|
|
|
request, self.user_name.data, self.repo_name.data
|
|
|
)
|
|
|
client.get_assignees()
|
|
|
except IntegrationException as e:
|
|
|
raise wtforms.validators.ValidationError(str(e))
|
|
|
raise wtforms.validators.ValidationError(str(e))
|
|
|
|
|
|
|
|
|
def filter_rooms(data):
|
|
|
if data is not None:
|
|
|
rooms = data.split(",")
|
|
|
return ",".join([r.strip() for r in rooms])
|
|
|
|
|
|
|
|
|
class IntegrationCampfireForm(ReactorForm):
|
|
|
account = wtforms.StringField(
|
|
|
"Account",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
api_token = wtforms.StringField(
|
|
|
"Api Token",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
rooms = wtforms.StringField("Room ID list", filters=[filter_rooms])
|
|
|
|
|
|
def validate_api_token(self, field):
|
|
|
try:
|
|
|
client = CampfireIntegration.create_client(
|
|
|
self.api_token.data, self.account.data
|
|
|
)
|
|
|
client.get_account()
|
|
|
except IntegrationException as e:
|
|
|
raise wtforms.validators.ValidationError(str(e))
|
|
|
|
|
|
def validate_rooms(self, field):
|
|
|
if not field.data:
|
|
|
return
|
|
|
client = CampfireIntegration.create_client(
|
|
|
self.api_token.data, self.account.data
|
|
|
)
|
|
|
|
|
|
try:
|
|
|
room_list = [r["id"] for r in client.get_rooms()]
|
|
|
except IntegrationException as e:
|
|
|
raise wtforms.validators.ValidationError(str(e))
|
|
|
|
|
|
rooms = field.data.split(",")
|
|
|
if len(rooms) > 3:
|
|
|
msg = "You can use up to 3 room ids"
|
|
|
raise wtforms.validators.ValidationError(msg)
|
|
|
if rooms:
|
|
|
for room_id in rooms:
|
|
|
if int(room_id) not in room_list:
|
|
|
msg = "Room %s doesn't exist"
|
|
|
raise wtforms.validators.ValidationError(msg % room_id)
|
|
|
if not room_id.strip().isdigit():
|
|
|
msg = "You must use only integers for room ids"
|
|
|
raise wtforms.validators.ValidationError(msg)
|
|
|
|
|
|
submit = wtforms.SubmitField(_("Connect to Campfire"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
def filter_rooms(data):
|
|
|
if data is not None:
|
|
|
rooms = data.split(",")
|
|
|
return ",".join([r.strip() for r in rooms])
|
|
|
|
|
|
|
|
|
class IntegrationHipchatForm(ReactorForm):
|
|
|
api_token = wtforms.StringField(
|
|
|
"Api Token",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
rooms = wtforms.StringField(
|
|
|
"Room ID list",
|
|
|
filters=[filter_rooms],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
def validate_rooms(self, field):
|
|
|
if not field.data:
|
|
|
return
|
|
|
client = HipchatIntegration.create_client(self.api_token.data)
|
|
|
rooms = field.data.split(",")
|
|
|
if len(rooms) > 3:
|
|
|
msg = "You can use up to 3 room ids"
|
|
|
raise wtforms.validators.ValidationError(msg)
|
|
|
if rooms:
|
|
|
for room_id in rooms:
|
|
|
if not room_id.strip().isdigit():
|
|
|
msg = "You must use only integers for room ids"
|
|
|
raise wtforms.validators.ValidationError(msg)
|
|
|
try:
|
|
|
client.send(
|
|
|
{
|
|
|
"message_format": "text",
|
|
|
"message": "testing for room existence",
|
|
|
"from": "AppEnlight",
|
|
|
"room_id": room_id,
|
|
|
"color": "green",
|
|
|
}
|
|
|
)
|
|
|
except IntegrationException as exc:
|
|
|
msg = "Room id: %s exception: %s"
|
|
|
raise wtforms.validators.ValidationError(msg % (room_id, exc))
|
|
|
|
|
|
|
|
|
class IntegrationFlowdockForm(ReactorForm):
|
|
|
api_token = wtforms.StringField(
|
|
|
"API Token",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
def validate_api_token(self, field):
|
|
|
try:
|
|
|
client = FlowdockIntegration.create_client(self.api_token.data)
|
|
|
registry = pyramid.threadlocal.get_current_registry()
|
|
|
payload = {
|
|
|
"source": registry.settings["mailing.from_name"],
|
|
|
"from_address": registry.settings["mailing.from_email"],
|
|
|
"subject": "Integration test",
|
|
|
"content": "If you can see this it was successful",
|
|
|
"tags": ["appenlight"],
|
|
|
"link": registry.settings["mailing.app_url"],
|
|
|
}
|
|
|
client.send_to_inbox(payload)
|
|
|
except IntegrationException as e:
|
|
|
raise wtforms.validators.ValidationError(str(e))
|
|
|
|
|
|
|
|
|
class IntegrationSlackForm(ReactorForm):
|
|
|
webhook_url = wtforms.StringField(
|
|
|
"Reports webhook",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
def validate_webhook_url(self, field):
|
|
|
registry = pyramid.threadlocal.get_current_registry()
|
|
|
client = SlackIntegration.create_client(field.data)
|
|
|
link = "<%s|%s>" % (
|
|
|
registry.settings["mailing.app_url"],
|
|
|
registry.settings["mailing.from_name"],
|
|
|
)
|
|
|
test_data = {
|
|
|
"username": "AppEnlight",
|
|
|
"icon_emoji": ":fire:",
|
|
|
"attachments": [
|
|
|
{
|
|
|
"fallback": "Testing integration channel: %s" % link,
|
|
|
"pretext": "Testing integration channel: %s" % link,
|
|
|
"color": "good",
|
|
|
"fields": [
|
|
|
{
|
|
|
"title": "Status",
|
|
|
"value": "Integration is working fine",
|
|
|
"short": False,
|
|
|
}
|
|
|
],
|
|
|
}
|
|
|
],
|
|
|
}
|
|
|
try:
|
|
|
client.make_request(data=test_data)
|
|
|
except IntegrationException as exc:
|
|
|
raise wtforms.validators.ValidationError(str(exc))
|
|
|
|
|
|
|
|
|
class IntegrationWebhooksForm(ReactorForm):
|
|
|
reports_webhook = wtforms.StringField(
|
|
|
"Reports webhook",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
alerts_webhook = wtforms.StringField(
|
|
|
"Alerts webhook",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
submit = wtforms.SubmitField(_("Setup webhooks"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-primary"}
|
|
|
|
|
|
|
|
|
class IntegrationJiraForm(ReactorForm):
|
|
|
host_name = wtforms.StringField(
|
|
|
"Server URL",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
user_name = wtforms.StringField(
|
|
|
"Username",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
password = wtforms.PasswordField(
|
|
|
"Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
project = wtforms.StringField(
|
|
|
"Project key",
|
|
|
filters=[uppercase_filter, strip_filter],
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
def validate_project(self, field):
|
|
|
if not field.data:
|
|
|
return
|
|
|
try:
|
|
|
client = JiraClient(
|
|
|
self.user_name.data,
|
|
|
self.password.data,
|
|
|
self.host_name.data,
|
|
|
self.project.data,
|
|
|
)
|
|
|
except Exception as exc:
|
|
|
raise wtforms.validators.ValidationError(str(exc))
|
|
|
|
|
|
room_list = [r.key.upper() for r in client.get_projects()]
|
|
|
if field.data.upper() not in room_list:
|
|
|
msg = "Project %s doesn\t exist in your Jira Instance"
|
|
|
raise wtforms.validators.ValidationError(msg % field.data)
|
|
|
|
|
|
|
|
|
def get_deletion_form(resource):
|
|
|
class F(ReactorForm):
|
|
|
application_name = wtforms.StringField(
|
|
|
"Application Name",
|
|
|
filters=[strip_filter],
|
|
|
validators=[wtforms.validators.AnyOf([resource.resource_name])],
|
|
|
)
|
|
|
resource_id = wtforms.HiddenField(default=resource.resource_id)
|
|
|
submit = wtforms.SubmitField(_("Delete my application"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-danger"}
|
|
|
|
|
|
return F
|
|
|
|
|
|
|
|
|
class ChangeApplicationOwnerForm(ReactorForm):
|
|
|
password = wtforms.PasswordField(
|
|
|
"Password",
|
|
|
filters=[strip_filter],
|
|
|
validators=[old_password_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
|
|
|
user_name = wtforms.StringField(
|
|
|
"New owners username",
|
|
|
filters=[strip_filter],
|
|
|
validators=[found_username_validator, wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
submit = wtforms.SubmitField(_("Transfer ownership of application"))
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-danger"}
|
|
|
|
|
|
|
|
|
def default_filename():
|
|
|
return "Invoice %s" % datetime.datetime.utcnow().strftime("%Y/%m")
|
|
|
|
|
|
|
|
|
class FileUploadForm(ReactorForm):
|
|
|
title = wtforms.StringField(
|
|
|
"File Title",
|
|
|
default=default_filename,
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
)
|
|
|
file = wtforms.FileField("File")
|
|
|
|
|
|
def validate_file(self, field):
|
|
|
if not hasattr(field.data, "file"):
|
|
|
raise wtforms.ValidationError("File is missing")
|
|
|
|
|
|
submit = wtforms.SubmitField(_("Upload"))
|
|
|
|
|
|
|
|
|
def get_partition_deletion_form(es_indices, pg_indices):
|
|
|
class F(ReactorForm):
|
|
|
es_index = wtforms.SelectMultipleField(
|
|
|
"Elasticsearch", choices=[(ix, "") for ix in es_indices]
|
|
|
)
|
|
|
pg_index = wtforms.SelectMultipleField(
|
|
|
"pg", choices=[(ix, "") for ix in pg_indices]
|
|
|
)
|
|
|
confirm = wtforms.TextField(
|
|
|
"Confirm",
|
|
|
filters=[uppercase_filter, strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.AnyOf(["CONFIRM"]),
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
ignore_labels = ["submit"]
|
|
|
css_classes = {"submit": "btn btn-danger"}
|
|
|
|
|
|
return F
|
|
|
|
|
|
|
|
|
class GroupCreateForm(ReactorForm):
|
|
|
group_name = wtforms.StringField(
|
|
|
_("Group Name"),
|
|
|
filters=[strip_filter],
|
|
|
validators=[
|
|
|
wtforms.validators.Length(min=2, max=50),
|
|
|
unique_groupname_validator,
|
|
|
wtforms.validators.DataRequired(),
|
|
|
],
|
|
|
)
|
|
|
description = wtforms.StringField(_("Group description"))
|
|
|
|
|
|
|
|
|
time_choices = [(k, v["label"]) for k, v in h.time_deltas.items()]
|
|
|
|
|
|
|
|
|
class AuthTokenCreateForm(ReactorForm):
|
|
|
description = wtforms.StringField(_("Token description"))
|
|
|
expires = wtforms.SelectField(
|
|
|
"Expires",
|
|
|
coerce=lambda x: x,
|
|
|
choices=time_choices,
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
)
|
|
|
|