# -*- 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 appenlight.models.user import User
from appenlight.models.group import Group
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 = ['
' % 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('
' % html_params(**options))
html.append('
' % (choice_id, label))
html.append('
')
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 = ['' % (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 = User.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 = User.by_email(field.data)
if not user:
raise wtforms.ValidationError('Email is incorrect')
def unique_username_validator(form, field):
user = User.by_user_name(field.data)
if user:
raise wtforms.ValidationError('This username already exists in system')
def unique_groupname_validator(form, field):
group = Group.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 = User.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 field.user.check_password(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 ``