##// END OF EJS Templates
forms: now that AE is open source this is not required
ergo -
Show More
@@ -1,903 +1,901 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # AppEnlight Enterprise Edition, including its added features, Support
19 19 # services, and proprietary license terms, please see
20 20 # https://rhodecode.com/licenses/
21 21
22 22 import wtforms
23 23 import formencode
24 24 import re
25 25 import pyramid.threadlocal
26 26 import datetime
27 27 import appenlight.lib.helpers as h
28 28
29 29 from appenlight.models.user import User
30 30 from appenlight.models.group import Group
31 31 from appenlight.models import DBSession
32 32 from appenlight.models.alert_channel import AlertChannel
33 33 from appenlight.models.integrations import IntegrationException
34 34 from appenlight.models.integrations.campfire import CampfireIntegration
35 35 from appenlight.models.integrations.bitbucket import BitbucketIntegration
36 36 from appenlight.models.integrations.github import GithubIntegration
37 37 from appenlight.models.integrations.flowdock import FlowdockIntegration
38 38 from appenlight.models.integrations.hipchat import HipchatIntegration
39 39 from appenlight.models.integrations.jira import JiraClient
40 40 from appenlight.models.integrations.slack import SlackIntegration
41 41 from appenlight.lib.ext_json import json
42 42 from wtforms.ext.csrf.form import SecureForm
43 43 from wtforms.compat import iteritems
44 44 from collections import defaultdict
45 45
46 46 _ = str
47 47
48 48 strip_filter = lambda x: x.strip() if x else None
49 49 uppercase_filter = lambda x: x.upper() if x else None
50 50
51 51 FALSE_VALUES = ('false', '', False, None)
52 52
53 53
54 54 class CSRFException(Exception):
55 55 pass
56 56
57 57
58 58 class ReactorForm(SecureForm):
59 59 def __init__(self, formdata=None, obj=None, prefix='', csrf_context=None,
60 60 **kwargs):
61 61 super(ReactorForm, self).__init__(formdata=formdata, obj=obj,
62 62 prefix=prefix,
63 63 csrf_context=csrf_context, **kwargs)
64 64 self._csrf_context = csrf_context
65 65
66 66 def generate_csrf_token(self, csrf_context):
67 67 return csrf_context.session.get_csrf_token()
68 68
69 69 def validate_csrf_token(self, field):
70 70 request = self._csrf_context or pyramid.threadlocal.get_current_request()
71 71 is_from_auth_token = 'auth:auth_token' in request.effective_principals
72 72 if is_from_auth_token:
73 73 return True
74 74
75 75 if field.data != field.current_token:
76 76 # try to save the day by using token from angular
77 77 if request.headers.get('X-XSRF-TOKEN') != field.current_token:
78 78 raise CSRFException('Invalid CSRF token')
79 79
80 80 @property
81 81 def errors_dict(self):
82 82 r_dict = defaultdict(list)
83 83 for k, errors in self.errors.items():
84 84 r_dict[k].extend([str(e) for e in errors])
85 85 return r_dict
86 86
87 87 @property
88 88 def errors_json(self):
89 89 return json.dumps(self.errors_dict)
90 90
91 91 def populate_obj(self, obj, ignore_none=False):
92 92 """
93 93 Populates the attributes of the passed `obj` with data from the form's
94 94 fields.
95 95
96 96 :note: This is a destructive operation; Any attribute with the same name
97 97 as a field will be overridden. Use with caution.
98 98 """
99 99 if ignore_none:
100 100 for name, field in iteritems(self._fields):
101 101 if field.data is not None:
102 102 field.populate_obj(obj, name)
103 103 else:
104 104 for name, field in iteritems(self._fields):
105 105 field.populate_obj(obj, name)
106 106
107 107 css_classes = {}
108 108 ignore_labels = {}
109 109
110 110
111 111 class SignInForm(ReactorForm):
112 112 came_from = wtforms.HiddenField()
113 113 sign_in_user_name = wtforms.StringField(_('User Name'))
114 114 sign_in_user_password = wtforms.PasswordField(_('Password'))
115 115
116 116 ignore_labels = ['submit']
117 117 css_classes = {'submit': 'btn btn-primary'}
118 118
119 119 html_attrs = {'sign_in_user_name': {'placeholder': 'Your login'},
120 120 'sign_in_user_password': {
121 121 'placeholder': 'Your password'}}
122 122
123 123
124 124 from wtforms.widgets import html_params, HTMLString
125 125
126 126
127 127 def select_multi_checkbox(field, ul_class='set', **kwargs):
128 128 """Render a multi-checkbox widget"""
129 129 kwargs.setdefault('type', 'checkbox')
130 130 field_id = kwargs.pop('id', field.id)
131 131 html = ['<ul %s>' % html_params(id=field_id, class_=ul_class)]
132 132 for value, label, checked in field.iter_choices():
133 133 choice_id = '%s-%s' % (field_id, value)
134 134 options = dict(kwargs, name=field.name, value=value, id=choice_id)
135 135 if checked:
136 136 options['checked'] = 'checked'
137 137 html.append('<li><input %s /> ' % html_params(**options))
138 138 html.append('<label for="%s">%s</label></li>' % (choice_id, label))
139 139 html.append('</ul>')
140 140 return HTMLString(''.join(html))
141 141
142 142
143 143 def button_widget(field, button_cls='ButtonField btn btn-default', **kwargs):
144 144 """Render a button widget"""
145 145 kwargs.setdefault('type', 'button')
146 146 field_id = kwargs.pop('id', field.id)
147 147 kwargs.setdefault('value', field.label.text)
148 148 html = ['<button %s>%s</button>' % (html_params(id=field_id,
149 149 class_=button_cls),
150 150 kwargs['value'],)]
151 151 return HTMLString(''.join(html))
152 152
153 153
154 154 def clean_whitespace(value):
155 155 if value:
156 156 return value.strip()
157 157 return value
158 158
159 159
160 160 def found_username_validator(form, field):
161 161 user = User.by_user_name(field.data)
162 162 # sets user to recover in email validator
163 163 form.field_user = user
164 164 if not user:
165 165 raise wtforms.ValidationError('This username does not exist')
166 166
167 167
168 168 def found_username_email_validator(form, field):
169 169 user = User.by_email(field.data)
170 170 if not user:
171 171 raise wtforms.ValidationError('Email is incorrect')
172 172
173 173
174 174 def unique_username_validator(form, field):
175 175 user = User.by_user_name(field.data)
176 176 if user:
177 177 raise wtforms.ValidationError('This username already exists in system')
178 178
179 179
180 180 def unique_groupname_validator(form, field):
181 181 group = Group.by_group_name(field.data)
182 182 mod_group = getattr(form, '_modified_group', None)
183 183 if group and (not mod_group or mod_group.id != group.id):
184 184 raise wtforms.ValidationError(
185 185 'This group name already exists in system')
186 186
187 187
188 188 def unique_email_validator(form, field):
189 189 user = User.by_email(field.data)
190 190 if user:
191 191 raise wtforms.ValidationError('This email already exists in system')
192 192
193 193
194 194 def email_validator(form, field):
195 195 validator = formencode.validators.Email()
196 196 try:
197 197 validator.to_python(field.data)
198 198 except formencode.Invalid as e:
199 199 raise wtforms.ValidationError(e)
200 200
201 201
202 202 def unique_alert_email_validator(form, field):
203 203 q = DBSession.query(AlertChannel)
204 204 q = q.filter(AlertChannel.channel_name == 'email')
205 205 q = q.filter(AlertChannel.channel_value == field.data)
206 206 email = q.first()
207 207 if email:
208 208 raise wtforms.ValidationError(
209 209 'This email already exists in alert system')
210 210
211 211
212 212 def blocked_email_validator(form, field):
213 213 blocked_emails = [
214 214 'goood-mail.org',
215 215 'shoeonlineblog.com',
216 216 'louboutinemart.com',
217 217 'guccibagshere.com',
218 218 'nikeshoesoutletforsale.com'
219 219 ]
220 220 data = field.data or ''
221 221 domain = data.split('@')[-1]
222 222 if domain in blocked_emails:
223 223 raise wtforms.ValidationError('Don\'t spam')
224 224
225 225
226 226 def old_password_validator(form, field):
227 227 if not field.user.check_password(field.data or ''):
228 228 raise wtforms.ValidationError('You need to enter correct password')
229 229
230 230
231 231 class UserRegisterForm(ReactorForm):
232 232 user_name = wtforms.StringField(
233 233 _('User Name'),
234 234 filters=[strip_filter],
235 235 validators=[
236 236 wtforms.validators.Length(min=2, max=30),
237 237 wtforms.validators.Regexp(
238 238 re.compile(r'^[\.\w-]+$', re.UNICODE),
239 239 message="Invalid characters used"),
240 240 unique_username_validator,
241 241 wtforms.validators.DataRequired()
242 242 ])
243 243
244 244 user_password = wtforms.PasswordField(_('User Password'),
245 245 filters=[strip_filter],
246 246 validators=[
247 247 wtforms.validators.Length(min=4),
248 248 wtforms.validators.DataRequired()
249 249 ])
250 250
251 251 email = wtforms.StringField(_('Email Address'),
252 252 filters=[strip_filter],
253 253 validators=[email_validator,
254 254 unique_email_validator,
255 255 blocked_email_validator,
256 wtforms.validators.DataRequired()],
257 description=_("We promise we will not share "
258 "your email with anyone"))
256 wtforms.validators.DataRequired()])
259 257 first_name = wtforms.HiddenField(_('First Name'))
260 258 last_name = wtforms.HiddenField(_('Last Name'))
261 259
262 260 ignore_labels = ['submit']
263 261 css_classes = {'submit': 'btn btn-primary'}
264 262
265 263 html_attrs = {'user_name': {'placeholder': 'Your login'},
266 264 'user_password': {'placeholder': 'Your password'},
267 265 'email': {'placeholder': 'Your email'}}
268 266
269 267
270 268 class UserCreateForm(UserRegisterForm):
271 269 status = wtforms.BooleanField('User status',
272 270 false_values=FALSE_VALUES)
273 271
274 272
275 273 class UserUpdateForm(UserCreateForm):
276 274 user_name = None
277 275 user_password = wtforms.PasswordField(_('User Password'),
278 276 filters=[strip_filter],
279 277 validators=[
280 278 wtforms.validators.Length(min=4),
281 279 wtforms.validators.Optional()
282 280 ])
283 281 email = wtforms.StringField(_('Email Address'),
284 282 filters=[strip_filter],
285 283 validators=[email_validator,
286 284 wtforms.validators.DataRequired()])
287 285
288 286
289 287 class LostPasswordForm(ReactorForm):
290 288 email = wtforms.StringField(_('Email Address'),
291 289 filters=[strip_filter],
292 290 validators=[email_validator,
293 291 found_username_email_validator,
294 292 wtforms.validators.DataRequired()])
295 293
296 294 submit = wtforms.SubmitField(_('Reset password'))
297 295 ignore_labels = ['submit']
298 296 css_classes = {'submit': 'btn btn-primary'}
299 297
300 298
301 299 class ChangePasswordForm(ReactorForm):
302 300 old_password = wtforms.PasswordField(
303 301 'Old Password',
304 302 filters=[strip_filter],
305 303 validators=[old_password_validator,
306 304 wtforms.validators.DataRequired()])
307 305
308 306 new_password = wtforms.PasswordField(
309 307 'New Password',
310 308 filters=[strip_filter],
311 309 validators=[wtforms.validators.Length(min=4),
312 310 wtforms.validators.DataRequired()])
313 311 new_password_confirm = wtforms.PasswordField(
314 312 'Confirm Password',
315 313 filters=[strip_filter],
316 314 validators=[wtforms.validators.EqualTo('new_password'),
317 315 wtforms.validators.DataRequired()])
318 316 submit = wtforms.SubmitField('Change Password')
319 317 ignore_labels = ['submit']
320 318 css_classes = {'submit': 'btn btn-primary'}
321 319
322 320
323 321 class CheckPasswordForm(ReactorForm):
324 322 password = wtforms.PasswordField(
325 323 'Password',
326 324 filters=[strip_filter],
327 325 validators=[old_password_validator,
328 326 wtforms.validators.DataRequired()])
329 327
330 328
331 329 class NewPasswordForm(ReactorForm):
332 330 new_password = wtforms.PasswordField(
333 331 'New Password',
334 332 filters=[strip_filter],
335 333 validators=[wtforms.validators.Length(min=4),
336 334 wtforms.validators.DataRequired()])
337 335 new_password_confirm = wtforms.PasswordField(
338 336 'Confirm Password',
339 337 filters=[strip_filter],
340 338 validators=[wtforms.validators.EqualTo('new_password'),
341 339 wtforms.validators.DataRequired()])
342 340 submit = wtforms.SubmitField('Set Password')
343 341 ignore_labels = ['submit']
344 342 css_classes = {'submit': 'btn btn-primary'}
345 343
346 344
347 345 class CORSTextAreaField(wtforms.StringField):
348 346 """
349 347 This field represents an HTML ``<textarea>`` and can be used to take
350 348 multi-line input.
351 349 """
352 350 widget = wtforms.widgets.TextArea()
353 351
354 352 def process_formdata(self, valuelist):
355 353 self.data = []
356 354 if valuelist:
357 355 data = [x.strip() for x in valuelist[0].split('\n')]
358 356 for d in data:
359 357 if not d:
360 358 continue
361 359 if d.startswith('www.'):
362 360 d = d[4:]
363 361 if data:
364 362 self.data.append(d)
365 363 else:
366 364 self.data = []
367 365 self.data = '\n'.join(self.data)
368 366
369 367
370 368 class ApplicationCreateForm(ReactorForm):
371 369 resource_name = wtforms.StringField(
372 370 _('Application name'),
373 371 filters=[strip_filter],
374 372 validators=[wtforms.validators.Length(min=1),
375 373 wtforms.validators.DataRequired()])
376 374
377 375 domains = CORSTextAreaField(
378 376 _('Domain names for CORS headers '),
379 377 validators=[wtforms.validators.Length(min=1),
380 378 wtforms.validators.Optional()],
381 379 description='Required for Javascript error '
382 380 'tracking (one line one domain, skip http:// part)')
383 381
384 382 submit = wtforms.SubmitField(_('Create Application'))
385 383
386 384 ignore_labels = ['submit']
387 385 css_classes = {'submit': 'btn btn-primary'}
388 386 html_attrs = {'resource_name': {'placeholder': 'Application Name'},
389 387 'uptime_url': {'placeholder': 'http://somedomain.com'}}
390 388
391 389
392 390 class ApplicationUpdateForm(ApplicationCreateForm):
393 391 default_grouping = wtforms.SelectField(
394 392 _('Default grouping for errors'),
395 393 choices=[('url_type', 'Error Type + location',),
396 394 ('url_traceback', 'Traceback + location',),
397 395 ('traceback_server', 'Traceback + Server',)],
398 396 default='url_traceback')
399 397
400 398 error_report_threshold = wtforms.IntegerField(
401 399 _('Alert on error reports'),
402 400 validators=[
403 401 wtforms.validators.NumberRange(min=1),
404 402 wtforms.validators.DataRequired()
405 403 ],
406 404 description='Application requires to send at least this amount of '
407 405 'error reports per minute to open alert'
408 406 )
409 407
410 408 slow_report_threshold = wtforms.IntegerField(
411 409 _('Alert on slow reports'),
412 410 validators=[wtforms.validators.NumberRange(min=1),
413 411 wtforms.validators.DataRequired()],
414 412 description='Application requires to send at least this amount of '
415 413 'slow reports per minute to open alert')
416 414
417 415 allow_permanent_storage = wtforms.BooleanField(
418 416 _('Permanent logs'),
419 417 false_values=FALSE_VALUES,
420 418 description=_(
421 419 'Allow permanent storage of logs in separate DB partitions'))
422 420
423 421 submit = wtforms.SubmitField(_('Create Application'))
424 422
425 423
426 424 class UserSearchSchemaForm(ReactorForm):
427 425 user_name = wtforms.StringField('User Name',
428 426 filters=[strip_filter], )
429 427
430 428 submit = wtforms.SubmitField(_('Search User'))
431 429 ignore_labels = ['submit']
432 430 css_classes = {'submit': 'btn btn-primary'}
433 431
434 432 '<li class="user_exists"><span></span></li>'
435 433
436 434
437 435 class YesNoForm(ReactorForm):
438 436 no = wtforms.SubmitField('No', default='')
439 437 yes = wtforms.SubmitField('Yes', default='')
440 438 ignore_labels = ['submit']
441 439 css_classes = {'submit': 'btn btn-primary'}
442 440
443 441
444 442 status_codes = [('', 'All',), ('500', '500',), ('404', '404',)]
445 443
446 444 priorities = [('', 'All',)]
447 445 for i in range(1, 11):
448 446 priorities.append((str(i), str(i),))
449 447
450 448 report_status_choices = [('', 'All',),
451 449 ('never_reviewed', 'Never revieved',),
452 450 ('reviewed', 'Revieved',),
453 451 ('public', 'Public',),
454 452 ('fixed', 'Fixed',), ]
455 453
456 454
457 455 class ReportBrowserForm(ReactorForm):
458 456 applications = wtforms.SelectMultipleField('Applications',
459 457 widget=select_multi_checkbox)
460 458 http_status = wtforms.SelectField('HTTP Status', choices=status_codes)
461 459 priority = wtforms.SelectField('Priority', choices=priorities, default='')
462 460 start_date = wtforms.DateField('Start Date')
463 461 end_date = wtforms.DateField('End Date')
464 462 error = wtforms.StringField('Error')
465 463 url_path = wtforms.StringField('URL Path')
466 464 url_domain = wtforms.StringField('URL Domain')
467 465 report_status = wtforms.SelectField('Report status',
468 466 choices=report_status_choices,
469 467 default='')
470 468 submit = wtforms.SubmitField('<span class="glyphicon glyphicon-search">'
471 469 '</span> Filter results',
472 470 widget=button_widget)
473 471
474 472 ignore_labels = ['submit']
475 473 css_classes = {'submit': 'btn btn-primary'}
476 474
477 475
478 476 slow_report_status_choices = [('', 'All',),
479 477 ('never_reviewed', 'Never revieved',),
480 478 ('reviewed', 'Revieved',),
481 479 ('public', 'Public',), ]
482 480
483 481
484 482 class BulkOperationForm(ReactorForm):
485 483 applications = wtforms.SelectField('Applications')
486 484 start_date = wtforms.DateField(
487 485 'Start Date',
488 486 default=lambda: datetime.datetime.utcnow() - datetime.timedelta(
489 487 days=90))
490 488 end_date = wtforms.DateField('End Date')
491 489 confirm = wtforms.BooleanField(
492 490 'Confirm operation',
493 491 validators=[wtforms.validators.DataRequired()])
494 492
495 493
496 494 class LogBrowserForm(ReactorForm):
497 495 applications = wtforms.SelectMultipleField('Applications',
498 496 widget=select_multi_checkbox)
499 497 start_date = wtforms.DateField('Start Date')
500 498 log_level = wtforms.StringField('Log level')
501 499 message = wtforms.StringField('Message')
502 500 namespace = wtforms.StringField('Namespace')
503 501 submit = wtforms.SubmitField(
504 502 '<span class="glyphicon glyphicon-search"></span> Filter results',
505 503 widget=button_widget)
506 504 ignore_labels = ['submit']
507 505 css_classes = {'submit': 'btn btn-primary'}
508 506
509 507
510 508 class CommentForm(ReactorForm):
511 509 body = wtforms.TextAreaField('Comment', validators=[
512 510 wtforms.validators.Length(min=1),
513 511 wtforms.validators.DataRequired()
514 512 ])
515 513 submit = wtforms.SubmitField('Comment', )
516 514 ignore_labels = ['submit']
517 515 css_classes = {'submit': 'btn btn-primary'}
518 516
519 517
520 518 class EmailChannelCreateForm(ReactorForm):
521 519 email = wtforms.StringField(_('Email Address'),
522 520 filters=[strip_filter],
523 521 validators=[email_validator,
524 522 unique_alert_email_validator,
525 523 wtforms.validators.DataRequired()])
526 524 submit = wtforms.SubmitField('Add email channel', )
527 525 ignore_labels = ['submit']
528 526 css_classes = {'submit': 'btn btn-primary'}
529 527
530 528
531 529 def gen_user_profile_form():
532 530 class UserProfileForm(ReactorForm):
533 531 email = wtforms.StringField(
534 532 _('Email Address'),
535 533 validators=[email_validator, wtforms.validators.DataRequired()])
536 534 first_name = wtforms.StringField(_('First Name'))
537 535 last_name = wtforms.StringField(_('Last Name'))
538 536 company_name = wtforms.StringField(_('Company Name'))
539 537 company_address = wtforms.TextAreaField(_('Company Address'))
540 538 zip_code = wtforms.StringField(_('ZIP code'))
541 539 city = wtforms.StringField(_('City'))
542 540 notifications = wtforms.BooleanField('Account notifications',
543 541 false_values=FALSE_VALUES)
544 542 submit = wtforms.SubmitField(_('Update Account'))
545 543 ignore_labels = ['submit']
546 544 css_classes = {'submit': 'btn btn-primary'}
547 545
548 546 return UserProfileForm
549 547
550 548
551 549 class PurgeAppForm(ReactorForm):
552 550 resource_id = wtforms.HiddenField(
553 551 'App Id',
554 552 validators=[wtforms.validators.DataRequired()])
555 553 days = wtforms.IntegerField(
556 554 'Days',
557 555 validators=[wtforms.validators.DataRequired()])
558 556 password = wtforms.PasswordField(
559 557 'Admin Password',
560 558 validators=[old_password_validator, wtforms.validators.DataRequired()])
561 559 submit = wtforms.SubmitField(_('Purge Data'))
562 560 ignore_labels = ['submit']
563 561 css_classes = {'submit': 'btn btn-primary'}
564 562
565 563
566 564 class IntegrationRepoForm(ReactorForm):
567 565 host_name = wtforms.StringField("Service Host", default='')
568 566 user_name = wtforms.StringField(
569 567 "User Name",
570 568 filters=[strip_filter],
571 569 validators=[wtforms.validators.DataRequired(),
572 570 wtforms.validators.Length(min=1)])
573 571 repo_name = wtforms.StringField(
574 572 "Repo Name",
575 573 filters=[strip_filter],
576 574 validators=[wtforms.validators.DataRequired(),
577 575 wtforms.validators.Length(min=1)])
578 576
579 577
580 578 class IntegrationBitbucketForm(IntegrationRepoForm):
581 579 host_name = wtforms.StringField("Service Host",
582 580 default='https://bitbucket.org')
583 581
584 582 def validate_user_name(self, field):
585 583 try:
586 584 request = pyramid.threadlocal.get_current_request()
587 585 client = BitbucketIntegration.create_client(
588 586 request,
589 587 self.user_name.data,
590 588 self.repo_name.data)
591 589 client.get_assignees()
592 590 except IntegrationException as e:
593 591 raise wtforms.validators.ValidationError(str(e))
594 592
595 593
596 594 class IntegrationGithubForm(IntegrationRepoForm):
597 595 host_name = wtforms.StringField("Service Host",
598 596 default='https://github.com')
599 597
600 598 def validate_user_name(self, field):
601 599 try:
602 600 request = pyramid.threadlocal.get_current_request()
603 601 client = GithubIntegration.create_client(
604 602 request,
605 603 self.user_name.data,
606 604 self.repo_name.data)
607 605 client.get_assignees()
608 606 except IntegrationException as e:
609 607 raise wtforms.validators.ValidationError(str(e))
610 608 raise wtforms.validators.ValidationError(str(e))
611 609
612 610
613 611 def filter_rooms(data):
614 612 if data is not None:
615 613 rooms = data.split(',')
616 614 return ','.join([r.strip() for r in rooms])
617 615
618 616
619 617 class IntegrationCampfireForm(ReactorForm):
620 618 account = wtforms.StringField(
621 619 'Account',
622 620 filters=[strip_filter],
623 621 validators=[wtforms.validators.DataRequired()])
624 622 api_token = wtforms.StringField(
625 623 'Api Token',
626 624 filters=[strip_filter],
627 625 validators=[wtforms.validators.DataRequired()])
628 626 rooms = wtforms.StringField('Room ID list', filters=[filter_rooms])
629 627
630 628 def validate_api_token(self, field):
631 629 try:
632 630 client = CampfireIntegration.create_client(self.api_token.data,
633 631 self.account.data)
634 632 client.get_account()
635 633 except IntegrationException as e:
636 634 raise wtforms.validators.ValidationError(str(e))
637 635
638 636 def validate_rooms(self, field):
639 637 if not field.data:
640 638 return
641 639 client = CampfireIntegration.create_client(self.api_token.data,
642 640 self.account.data)
643 641
644 642 try:
645 643 room_list = [r['id'] for r in client.get_rooms()]
646 644 except IntegrationException as e:
647 645 raise wtforms.validators.ValidationError(str(e))
648 646
649 647 rooms = field.data.split(',')
650 648 if len(rooms) > 3:
651 649 msg = 'You can use up to 3 room ids'
652 650 raise wtforms.validators.ValidationError(msg)
653 651 if rooms:
654 652 for room_id in rooms:
655 653 if int(room_id) not in room_list:
656 654 msg = "Room %s doesn't exist"
657 655 raise wtforms.validators.ValidationError(msg % room_id)
658 656 if not room_id.strip().isdigit():
659 657 msg = 'You must use only integers for room ids'
660 658 raise wtforms.validators.ValidationError(msg)
661 659
662 660 submit = wtforms.SubmitField(_('Connect to Campfire'))
663 661 ignore_labels = ['submit']
664 662 css_classes = {'submit': 'btn btn-primary'}
665 663
666 664
667 665 def filter_rooms(data):
668 666 if data is not None:
669 667 rooms = data.split(',')
670 668 return ','.join([r.strip() for r in rooms])
671 669
672 670
673 671 class IntegrationHipchatForm(ReactorForm):
674 672 api_token = wtforms.StringField(
675 673 'Api Token',
676 674 filters=[strip_filter],
677 675 validators=[wtforms.validators.DataRequired()])
678 676 rooms = wtforms.StringField(
679 677 'Room ID list',
680 678 filters=[filter_rooms],
681 679 validators=[wtforms.validators.DataRequired()])
682 680
683 681 def validate_rooms(self, field):
684 682 if not field.data:
685 683 return
686 684 client = HipchatIntegration.create_client(self.api_token.data)
687 685 rooms = field.data.split(',')
688 686 if len(rooms) > 3:
689 687 msg = 'You can use up to 3 room ids'
690 688 raise wtforms.validators.ValidationError(msg)
691 689 if rooms:
692 690 for room_id in rooms:
693 691 if not room_id.strip().isdigit():
694 692 msg = 'You must use only integers for room ids'
695 693 raise wtforms.validators.ValidationError(msg)
696 694 try:
697 695 client.send({
698 696 "message_format": 'text',
699 697 "message": "testing for room existence",
700 698 "from": "AppEnlight",
701 699 "room_id": room_id,
702 700 "color": "green"
703 701 })
704 702 except IntegrationException as exc:
705 703 msg = 'Room id: %s exception: %s'
706 704 raise wtforms.validators.ValidationError(msg % (room_id,
707 705 exc))
708 706
709 707
710 708 class IntegrationFlowdockForm(ReactorForm):
711 709 api_token = wtforms.StringField('API Token',
712 710 filters=[strip_filter],
713 711 validators=[
714 712 wtforms.validators.DataRequired()
715 713 ], )
716 714
717 715 def validate_api_token(self, field):
718 716 try:
719 717 client = FlowdockIntegration.create_client(self.api_token.data)
720 718 registry = pyramid.threadlocal.get_current_registry()
721 719 payload = {
722 720 "source": registry.settings['mailing.from_name'],
723 721 "from_address": registry.settings['mailing.from_email'],
724 722 "subject": "Integration test",
725 723 "content": "If you can see this it was successful",
726 724 "tags": ["appenlight"],
727 725 "link": registry.settings['mailing.app_url']
728 726 }
729 727 client.send_to_inbox(payload)
730 728 except IntegrationException as e:
731 729 raise wtforms.validators.ValidationError(str(e))
732 730
733 731
734 732 class IntegrationSlackForm(ReactorForm):
735 733 webhook_url = wtforms.StringField(
736 734 'Reports webhook',
737 735 filters=[strip_filter],
738 736 validators=[wtforms.validators.DataRequired()])
739 737
740 738 def validate_webhook_url(self, field):
741 739 registry = pyramid.threadlocal.get_current_registry()
742 740 client = SlackIntegration.create_client(field.data)
743 741 link = "<%s|%s>" % (registry.settings['mailing.app_url'],
744 742 registry.settings['mailing.from_name'])
745 743 test_data = {
746 744 "username": "AppEnlight",
747 745 "icon_emoji": ":fire:",
748 746 "attachments": [
749 747 {"fallback": "Testing integration channel: %s" % link,
750 748 "pretext": "Testing integration channel: %s" % link,
751 749 "color": "good",
752 750 "fields": [
753 751 {
754 752 "title": "Status",
755 753 "value": "Integration is working fine",
756 754 "short": False
757 755 }
758 756 ]}
759 757 ]
760 758 }
761 759 try:
762 760 client.make_request(data=test_data)
763 761 except IntegrationException as exc:
764 762 raise wtforms.validators.ValidationError(str(exc))
765 763
766 764
767 765 class IntegrationWebhooksForm(ReactorForm):
768 766 reports_webhook = wtforms.StringField(
769 767 'Reports webhook',
770 768 filters=[strip_filter],
771 769 validators=[wtforms.validators.DataRequired()])
772 770 alerts_webhook = wtforms.StringField(
773 771 'Alerts webhook',
774 772 filters=[strip_filter],
775 773 validators=[wtforms.validators.DataRequired()])
776 774 submit = wtforms.SubmitField(_('Setup webhooks'))
777 775 ignore_labels = ['submit']
778 776 css_classes = {'submit': 'btn btn-primary'}
779 777
780 778
781 779 class IntegrationJiraForm(ReactorForm):
782 780 host_name = wtforms.StringField(
783 781 'Server URL',
784 782 filters=[strip_filter],
785 783 validators=[wtforms.validators.DataRequired()])
786 784 user_name = wtforms.StringField(
787 785 'Username',
788 786 filters=[strip_filter],
789 787 validators=[wtforms.validators.DataRequired()])
790 788 password = wtforms.PasswordField(
791 789 'Password',
792 790 filters=[strip_filter],
793 791 validators=[wtforms.validators.DataRequired()])
794 792 project = wtforms.StringField(
795 793 'Project key',
796 794 filters=[uppercase_filter, strip_filter],
797 795 validators=[wtforms.validators.DataRequired()])
798 796
799 797 def validate_project(self, field):
800 798 if not field.data:
801 799 return
802 800 try:
803 801 client = JiraClient(self.user_name.data,
804 802 self.password.data,
805 803 self.host_name.data,
806 804 self.project.data)
807 805 except Exception as exc:
808 806 raise wtforms.validators.ValidationError(str(exc))
809 807
810 808 room_list = [r.key.upper() for r in client.get_projects()]
811 809 if field.data.upper() not in room_list:
812 810 msg = "Project %s doesn\t exist in your Jira Instance"
813 811 raise wtforms.validators.ValidationError(msg % field.data)
814 812
815 813
816 814 def get_deletion_form(resource):
817 815 class F(ReactorForm):
818 816 application_name = wtforms.StringField(
819 817 'Application Name',
820 818 filters=[strip_filter],
821 819 validators=[wtforms.validators.AnyOf([resource.resource_name])])
822 820 resource_id = wtforms.HiddenField(default=resource.resource_id)
823 821 submit = wtforms.SubmitField(_('Delete my application'))
824 822 ignore_labels = ['submit']
825 823 css_classes = {'submit': 'btn btn-danger'}
826 824
827 825 return F
828 826
829 827
830 828 class ChangeApplicationOwnerForm(ReactorForm):
831 829 password = wtforms.PasswordField(
832 830 'Password',
833 831 filters=[strip_filter],
834 832 validators=[old_password_validator,
835 833 wtforms.validators.DataRequired()])
836 834
837 835 user_name = wtforms.StringField(
838 836 'New owners username',
839 837 filters=[strip_filter],
840 838 validators=[found_username_validator,
841 839 wtforms.validators.DataRequired()])
842 840 submit = wtforms.SubmitField(_('Transfer ownership of application'))
843 841 ignore_labels = ['submit']
844 842 css_classes = {'submit': 'btn btn-danger'}
845 843
846 844
847 845 def default_filename():
848 846 return 'Invoice %s' % datetime.datetime.utcnow().strftime('%Y/%m')
849 847
850 848
851 849 class FileUploadForm(ReactorForm):
852 850 title = wtforms.StringField('File Title',
853 851 default=default_filename,
854 852 validators=[wtforms.validators.DataRequired()])
855 853 file = wtforms.FileField('File')
856 854
857 855 def validate_file(self, field):
858 856 if not hasattr(field.data, 'file'):
859 857 raise wtforms.ValidationError('File is missing')
860 858
861 859 submit = wtforms.SubmitField(_('Upload'))
862 860
863 861
864 862 def get_partition_deletion_form(es_indices, pg_indices):
865 863 class F(ReactorForm):
866 864 es_index = wtforms.SelectMultipleField('Elasticsearch',
867 865 choices=[(ix, '') for ix in
868 866 es_indices])
869 867 pg_index = wtforms.SelectMultipleField('pg',
870 868 choices=[(ix, '') for ix in
871 869 pg_indices])
872 870 confirm = wtforms.TextField('Confirm',
873 871 filters=[uppercase_filter, strip_filter],
874 872 validators=[
875 873 wtforms.validators.AnyOf(['CONFIRM']),
876 874 wtforms.validators.DataRequired()])
877 875 ignore_labels = ['submit']
878 876 css_classes = {'submit': 'btn btn-danger'}
879 877
880 878 return F
881 879
882 880
883 881 class GroupCreateForm(ReactorForm):
884 882 group_name = wtforms.StringField(
885 883 _('Group Name'),
886 884 filters=[strip_filter],
887 885 validators=[
888 886 wtforms.validators.Length(min=2, max=50),
889 887 unique_groupname_validator,
890 888 wtforms.validators.DataRequired()
891 889 ])
892 890 description = wtforms.StringField(_('Group description'))
893 891
894 892
895 893 time_choices = [(k, v['label'],) for k, v in h.time_deltas.items()]
896 894
897 895
898 896 class AuthTokenCreateForm(ReactorForm):
899 897 description = wtforms.StringField(_('Token description'))
900 898 expires = wtforms.SelectField('Expires',
901 899 coerce=lambda x: x,
902 900 choices=time_choices,
903 901 validators=[wtforms.validators.Optional()])
General Comments 0
You need to be logged in to leave comments. Login now