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